diff options
| author | Fariborz Jahanian <fjahanian@apple.com> | 2014-09-18 17:58:27 +0000 |
|---|---|---|
| committer | Fariborz Jahanian <fjahanian@apple.com> | 2014-09-18 17:58:27 +0000 |
| commit | 3e6a0be4c4531d97134daea5bd32c5564e3d34f5 (patch) | |
| tree | 4aebd6f3e972295c7c35cee5fe687efb9a78e7fa /clang/lib/Sema | |
| parent | 0bb041b5f405f1e2fba5bff66357f709221499a4 (diff) | |
| download | bcm5719-llvm-3e6a0be4c4531d97134daea5bd32c5564e3d34f5.tar.gz bcm5719-llvm-3e6a0be4c4531d97134daea5bd32c5564e3d34f5.zip | |
Patch to check at compile time for overflow when
__builtin___memcpy_chk and similar builtins are
being used. Patch by Jacques Fortier (with added
clang tests). rdar://11076881
llvm-svn: 218063
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 49 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 |
2 files changed, 50 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 953b3f67d2f..74628693063 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -111,8 +111,37 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return false; } +static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, + CallExpr *TheCall, unsigned SizeIdx, + unsigned DstSizeIdx) { + if (TheCall->getNumArgs() <= SizeIdx || + TheCall->getNumArgs() <= DstSizeIdx) + return; + + const Expr *SizeArg = TheCall->getArg(SizeIdx); + const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx); + + llvm::APSInt Size, DstSize; + + // find out if both sizes are known at compile time + if (!SizeArg->EvaluateAsInt(Size, S.Context) || + !DstSizeArg->EvaluateAsInt(DstSize, S.Context)) + return; + + if (Size.ule(DstSize)) + return; + + // confirmed overflow so generate the diagnostic. + IdentifierInfo *FnName = FDecl->getIdentifier(); + SourceLocation SL = TheCall->getLocStart(); + SourceRange SR = TheCall->getSourceRange(); + + S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName; +} + ExprResult -Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, + CallExpr *TheCall) { ExprResult TheCallResult(TheCall); // Find out if any arguments are required to be integer constant expressions. @@ -332,6 +361,24 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { // so ensure that they are declared. DeclareGlobalNewDelete(); break; + + // check secure string manipulation functions where overflows + // are detectable at compile time + case Builtin::BI__builtin___memcpy_chk: + case Builtin::BI__builtin___memccpy_chk: + case Builtin::BI__builtin___memmove_chk: + case Builtin::BI__builtin___memset_chk: + case Builtin::BI__builtin___strlcat_chk: + case Builtin::BI__builtin___strlcpy_chk: + case Builtin::BI__builtin___strncat_chk: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BI__builtin___stpncpy_chk: + SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3); + break; + case Builtin::BI__builtin___snprintf_chk: + case Builtin::BI__builtin___vsnprintf_chk: + SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); + break; } // Since the target specific builtins for each arch overlap, only check those diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6b01b1f4b0c..50bc4d2ac8b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4665,7 +4665,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Bail out early if calling a builtin with custom typechecking. if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) - return CheckBuiltinFunctionCall(BuiltinID, TheCall); + return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); retry: const FunctionType *FuncT; @@ -4793,7 +4793,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, return ExprError(); if (BuiltinID) - return CheckBuiltinFunctionCall(BuiltinID, TheCall); + return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); } else if (NDecl) { if (CheckPointerCall(NDecl, TheCall, Proto)) return ExprError(); |

