diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2019-02-11 23:21:39 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2019-02-11 23:21:39 +0000 |
commit | e3cd735ea6378e5dd7765828f560ed49be845a95 (patch) | |
tree | 91101427ae598d9ea6ced7a2e44f0f4f209fe4a9 /clang/lib/CodeGen/CGBuiltin.cpp | |
parent | 796ac80b863ed92c3d8bcc296f678ff416afc8a8 (diff) | |
download | bcm5719-llvm-e3cd735ea6378e5dd7765828f560ed49be845a95.tar.gz bcm5719-llvm-e3cd735ea6378e5dd7765828f560ed49be845a95.zip |
Add a new attribute, fortify_stdlib
This attribute applies to declarations of C stdlib functions
(sprintf, memcpy...) that have known fortified variants
(__sprintf_chk, __memcpy_chk, ...). When applied, clang will emit
calls to the fortified variant functions instead of calls to the
defaults.
In GCC, this is done by adding gnu_inline-style wrapper functions,
but that doesn't work for us for variadic functions because we don't
support __builtin_va_arg_pack (and have no intention to).
This attribute takes two arguments, the first is 'type' argument
passed through to __builtin_object_size, and the second is a flag
argument that gets passed through to the variadic checking variants.
rdar://47905754
Differential revision: https://reviews.llvm.org/D57918
llvm-svn: 353765
Diffstat (limited to 'clang/lib/CodeGen/CGBuiltin.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a528bff59c4..fd5a6ab8ff3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1474,6 +1474,86 @@ RValue CodeGenFunction::emitRotate(const CallExpr *E, bool IsRotateRight) { return RValue::get(Builder.CreateCall(F, { Src, Src, ShiftAmt })); } +/// For a call to a builtin C standard library function, emit a call to a +/// fortified variant using __builtin_object_size. For instance, instead of +/// emitting `sprintf(buf, "%d", 32)`, this function would emit +/// `__sprintf_chk(buf, Flag, __builtin_object_size(buf, 0), "%d", 32)`. +RValue CodeGenFunction::emitFortifiedStdLibCall(CodeGenFunction &CGF, + const CallExpr *CE, + unsigned BuiltinID, + unsigned BOSType, + unsigned Flag) { + SmallVector<llvm::Value *, 8> ArgVals; + for (const Expr *Arg : CE->arguments()) + ArgVals.push_back(EmitScalarExpr(Arg)); + + llvm::Value *FlagVal = llvm::ConstantInt::get(IntTy, Flag); + auto emitObjSize = [&]() { + return evaluateOrEmitBuiltinObjectSize(CE->getArg(0), BOSType, SizeTy, + ArgVals[0], false); + }; + + unsigned FortifiedVariantID = Builtin::getFortifiedVariantFunction(BuiltinID); + assert(FortifiedVariantID != 0 && "Should be diagnosed in Sema"); + + // Adjust ArgVals to include a __builtin_object_size(n) or flag argument at + // the right position. Variadic printf-like functions take a flag and object + // size (if they're printing to a string) before the format string, and all + // other functions just take the object size as their last argument. The + // object size, if present, always corresponds to the first argument. + switch (BuiltinID) { + case Builtin::BImemcpy: + case Builtin::BImemmove: + case Builtin::BImemset: + case Builtin::BIstpcpy: + case Builtin::BIstrcat: + case Builtin::BIstrcpy: + case Builtin::BIstrlcat: + case Builtin::BIstrlcpy: + case Builtin::BIstrncat: + case Builtin::BIstrncpy: + case Builtin::BIstpncpy: + ArgVals.push_back(emitObjSize()); + break; + + case Builtin::BIsnprintf: + case Builtin::BIvsnprintf: + ArgVals.insert(ArgVals.begin() + 2, FlagVal); + ArgVals.insert(ArgVals.begin() + 3, emitObjSize()); + break; + + case Builtin::BIsprintf: + case Builtin::BIvsprintf: + ArgVals.insert(ArgVals.begin() + 1, FlagVal); + ArgVals.insert(ArgVals.begin() + 2, emitObjSize()); + break; + + case Builtin::BIfprintf: + case Builtin::BIvfprintf: + ArgVals.insert(ArgVals.begin() + 1, FlagVal); + break; + + case Builtin::BIprintf: + case Builtin::BIvprintf: + ArgVals.insert(ArgVals.begin(), FlagVal); + break; + + default: + llvm_unreachable("Unknown fortified builtin?"); + } + + ASTContext::GetBuiltinTypeError Err; + QualType VariantTy = getContext().GetBuiltinType(FortifiedVariantID, Err); + assert(Err == ASTContext::GE_None && "Should not codegen an error"); + auto *LLVMVariantTy = cast<llvm::FunctionType>(ConvertType(VariantTy)); + StringRef VariantName = getContext().BuiltinInfo.getName(FortifiedVariantID) + + strlen("__builtin_"); + + llvm::Value *V = Builder.CreateCall( + CGM.CreateRuntimeFunction(LLVMVariantTy, VariantName), ArgVals); + return RValue::get(V); +} + RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -1490,6 +1570,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Result.Val.getFloat())); } + if (const auto *FortifyAttr = FD->getAttr<FortifyStdLibAttr>()) + return emitFortifiedStdLibCall(*this, E, BuiltinID, FortifyAttr->getType(), + FortifyAttr->getFlag()); + // There are LLVM math intrinsics/instructions corresponding to math library // functions except the LLVM op will never set errno while the math library // might. Also, math builtins have the same semantics as their math library |