diff options
-rw-r--r-- | include/clang/AST/Attr.h | 10 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 8 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 92 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 10 |
5 files changed, 83 insertions, 52 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 2f4fa228e5..685a90b4fa 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -14,6 +14,9 @@ #ifndef LLVM_CLANG_AST_ATTR_H #define LLVM_CLANG_AST_ATTR_H +#include "llvm/Support/Casting.h" +using llvm::dyn_cast; + #include <cassert> #include <cstring> #include <string> @@ -121,6 +124,13 @@ public: const Attr *getNext() const { return Next; } void setNext(Attr *next) { Next = next; } + template<typename T> const T *getNext() const { + for (const Attr *attr = getNext(); attr; attr = attr->getNext()) + if (const T *V = dyn_cast<T>(attr)) + return V; + return 0; + } + bool isInherited() const { return Inherited; } void setInherited(bool value) { Inherited = value; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fab6bcf604..d17e2f1498 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3336,14 +3336,16 @@ public: //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system private: - Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl, - CallExpr *TheCall); + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); + bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); - Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall); bool CheckObjCString(Expr *Arg); + + Action::OwningExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinStackAddress(CallExpr *TheCall); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index ffe4abd731..612c4dc4cb 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -100,31 +100,22 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { return false; } -/// CheckFunctionCall - Check a direct function call for various correctness -/// and safety properties not strictly enforced by the C type system. Action::OwningExprResult -Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { +Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { OwningExprResult TheCallResult(Owned(TheCall)); - // Get the IdentifierInfo* for the called function. - IdentifierInfo *FnInfo = FDecl->getIdentifier(); - - // None of the checks below are needed for functions that don't have - // simple names (e.g., C++ conversion functions). - if (!FnInfo) - return move(TheCallResult); - switch (FDecl->getBuiltinID(Context)) { + switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && "Wrong # arguments to builtin CFStringMakeConstantString"); if (CheckObjCString(TheCall->getArg(0))) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: if (SemaBuiltinVAStart(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -133,12 +124,12 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__builtin_isunordered: if (SemaBuiltinUnorderedCompare(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_return_address: case Builtin::BI__builtin_frame_address: if (SemaBuiltinStackAddress(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_shufflevector: return SemaBuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since @@ -146,15 +137,15 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__builtin_prefetch: if (SemaBuiltinPrefetch(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_object_size: if (SemaBuiltinObjectSize(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_longjmp: if (SemaBuiltinLongjmp(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_or: @@ -173,9 +164,23 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__sync_lock_release: if (SemaBuiltinAtomicOverloaded(TheCall)) return ExprError(); - return move(TheCallResult); + break; } + + return move(TheCallResult); +} +/// CheckFunctionCall - Check a direct function call for various correctness +/// and safety properties not strictly enforced by the C type system. +bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { + // Get the IdentifierInfo* for the called function. + IdentifierInfo *FnInfo = FDecl->getIdentifier(); + + // None of the checks below are needed for functions that don't have + // simple names (e.g., C++ conversion functions). + if (!FnInfo) + return false; + // FIXME: This mechanism should be abstracted to be less fragile and // more efficient. For example, just map function ids to custom // handlers. @@ -193,41 +198,42 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { HasVAListArg ? 0 : Format->getFirstArg() - 1); } } - for (const Attr *attr = FDecl->getAttrs(); - attr; attr = attr->getNext()) { - if (const NonNullAttr *NonNull = dyn_cast<NonNullAttr>(attr)) - CheckNonNullArguments(NonNull, TheCall); - } + + for (const NonNullAttr *NonNull = FDecl->getAttr<NonNullAttr>(); NonNull; + NonNull = NonNull->getNext<NonNullAttr>()) + CheckNonNullArguments(NonNull, TheCall); - return move(TheCallResult); + return false; } -Action::OwningExprResult -Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { - - OwningExprResult TheCallResult(Owned(TheCall)); +bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { // Printf checking. const FormatAttr *Format = NDecl->getAttr<FormatAttr>(); if (!Format) - return move(TheCallResult); + return false; + const VarDecl *V = dyn_cast<VarDecl>(NDecl); if (!V) - return move(TheCallResult); + return false; + QualType Ty = V->getType(); if (!Ty->isBlockPointerType()) - return move(TheCallResult); - if (CheckablePrintfAttr(Format, TheCall)) { - bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - const FunctionType *FT = - Ty->getAs<BlockPointerType>()->getPointeeType()->getAsFunctionType(); - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - HasVAListArg = !Proto->isVariadic(); - } - CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, - HasVAListArg ? 0 : Format->getFirstArg() - 1); + return false; + + if (!CheckablePrintfAttr(Format, TheCall)) + return false; + + bool HasVAListArg = Format->getFirstArg() == 0; + if (!HasVAListArg) { + const FunctionType *FT = + Ty->getAs<BlockPointerType>()->getPointeeType()->getAsFunctionType(); + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) + HasVAListArg = !Proto->isVariadic(); } - return move(TheCallResult); + CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1); + + return false; } /// SemaBuiltinAtomicOverloaded - We have a call to a function like diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1a519ffc1b..5f1467c733 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2929,11 +2929,18 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // Check for sentinels if (NDecl) DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs); + // Do special checking on direct calls to functions. - if (FDecl) - return CheckFunctionCall(FDecl, TheCall.take()); - if (NDecl) - return CheckBlockCall(NDecl, TheCall.take()); + if (FDecl) { + if (CheckFunctionCall(FDecl, TheCall.get())) + return ExprError(); + + if (unsigned BuiltinID = FDecl->getBuiltinID(Context)) + return CheckBuiltinFunctionCall(BuiltinID, TheCall.take()); + } else if (NDecl) { + if (CheckBlockCall(NDecl, TheCall.get())) + return ExprError(); + } return Owned(TheCall.take()); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index faf4d82a8b..d45e54a4a5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4343,7 +4343,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, RParenLoc)) return true; - return CheckFunctionCall(Method, TheCall.take()).release(); + if (CheckFunctionCall(Method, TheCall.get())) + return true; + + return TheCall.release(); } /// BuildCallToObjectOfClassType - Build a call to an object of class @@ -4549,7 +4552,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (IsError) return true; - return CheckFunctionCall(Method, TheCall.take()).release(); + if (CheckFunctionCall(Method, TheCall.get())) + return true; + + return TheCall.release(); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> |