From: Peter Collingbourne Date: Sun, 16 Oct 2011 21:17:32 +0000 (+0000) Subject: Add sema checks for calls to functions taking static array parameters X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20cdbeb8f36576f469db195b4140c293c7281718;p=clang Add sema checks for calls to functions taking static array parameters git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142157 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2662a19691..33175a29e5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2716,6 +2716,9 @@ def ext_typecheck_zero_array_size : Extension< "zero size arrays are an extension">; def err_typecheck_zero_array_size : Error< "zero-length arrays are not permitted in C++">; +def warn_typecheck_zero_static_array_size : Warning< + "'static' has no effect on zero-length arrays">, + InGroup>; def err_at_least_one_initializer_needed_to_size_array : Error< "at least one initializer value required to size array">; def err_array_size_non_int : Error<"size of array has non-integer type %0">; @@ -4509,6 +4512,11 @@ def warn_format_mix_positional_nonpositional_args : Warning< def warn_null_arg : Warning< "null passed to a callee which requires a non-null argument">, InGroup; +def warn_static_array_too_small : Warning< + "array argument is too small; contains %0 elements, callee requires at least %1">, + InGroup>; +def note_callee_static_array : Note< + "callee declares array parameter as static here">; def warn_empty_format_string : Warning< "format string is empty">, InGroup; def warn_format_string_is_wide_literal : Warning< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 775dc1283d..4f244db737 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6103,6 +6103,10 @@ private: const Expr * const *ExprArgs, SourceLocation CallSiteLoc); + void CheckStaticArrayArguments(const FunctionDecl *FDecl, + const Expr * const *ExprArgs, + SourceLocation CallSiteLoc); + void CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, bool isPrintf); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 310138354b..329adf89e8 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -360,6 +360,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } + CheckStaticArrayArguments(FDecl, TheCall->getArgs(), + TheCall->getCallee()->getLocStart()); + // Builtin handling int CMF = -1; switch (FDecl->getBuiltinID()) { @@ -1362,6 +1365,64 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, } } +static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) { + TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc(); + if (ArrayTypeLoc *ATL = dyn_cast(&TL)) + S.Diag(PVD->getLocation(), diag::note_callee_static_array) + << ATL->getLocalSourceRange(); +} + +/// CheckStaticArrayArguments - Check that each argument corresponding to a +/// static array parameter is non-null, and that if it is formed by +/// array-to-pointer decay, the underlying array is sufficiently large. +/// +/// C99 6.7.5.3p7: If the keyword static also appears within the [ and ] of the +/// array type derivation, then for each call to the function, the value of the +/// corresponding actual argument shall provide access to the first element of +/// an array with at least as many elements as specified by the size expression. +void +Sema::CheckStaticArrayArguments(const FunctionDecl *FDecl, + const Expr * const *ExprArgs, + SourceLocation CallSiteLoc) { + // Static array parameters are not supported in C++. + if (getLangOptions().CPlusPlus) + return; + + for (FunctionDecl::param_const_iterator i = FDecl->param_begin(), + e = FDecl->param_end(); i != e; ++i, ++ExprArgs) { + const Expr *ArgExpr = *ExprArgs; + QualType OrigTy = (*i)->getOriginalType(); + + const ArrayType *AT = Context.getAsArrayType(OrigTy); + if (!AT || AT->getSizeModifier() != ArrayType::Static) + continue; + + if (ArgExpr->isNullPointerConstant(Context, + Expr::NPC_NeverValueDependent)) { + Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange(); + DiagnoseCalleeStaticArrayParam(*this, *i); + continue; + } + + const ConstantArrayType *CAT = dyn_cast(AT); + if (!CAT) + continue; + + const ConstantArrayType *ArgCAT = + Context.getAsConstantArrayType(ArgExpr->IgnoreParenImpCasts()->getType()); + if (!ArgCAT) + continue; + + if (ArgCAT->getSize().ult(CAT->getSize())) { + Diag(CallSiteLoc, diag::warn_static_array_too_small) + << ArgExpr->getSourceRange() + << (unsigned) ArgCAT->getSize().getZExtValue() + << (unsigned) CAT->getSize().getZExtValue(); + DiagnoseCalleeStaticArrayParam(*this, *i); + } + } +} + /// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar /// functions) for correct use of format strings. void diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index d3a39967de..fe5b719591 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1315,6 +1315,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, isSFINAEContext()? diag::err_typecheck_zero_array_size : diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); + + if (ASM == ArrayType::Static) { + Diag(ArraySize->getLocStart(), + diag::warn_typecheck_zero_static_array_size) + << ArraySize->getSourceRange(); + ASM = ArrayType::Normal; + } } else if (!T->isDependentType() && !T->isVariablyModifiedType() && !T->isIncompleteType()) { // Is the array too large? diff --git a/test/Sema/static-array.c b/test/Sema/static-array.c new file mode 100644 index 0000000000..2d4b968dec --- /dev/null +++ b/test/Sema/static-array.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void cat0(int a[static 0]) {} // expected-warning {{'static' has no effect on zero-length arrays}} + +void cat(int a[static 3]) {} // expected-note 2 {{callee declares array parameter as static here}} + +typedef int i3[static 3]; +void tcat(i3 a) {} + +void vat(int i, int a[static i]) {} // expected-note {{callee declares array parameter as static here}} + +void f(int *p) { + int a[2], b[3], c[4]; + + cat0(0); + + cat(0); // expected-warning {{null passed to a callee which requires a non-null argument}} + cat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}} + cat(b); + cat(c); + cat(p); + + tcat(0); // expected-warning {{null passed to a callee which requires a non-null argument}} + tcat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}} + tcat(b); + tcat(c); + tcat(p); + + vat(1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}} + vat(3, b); +}