summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGBuiltin.cpp
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2019-02-11 23:21:39 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2019-02-11 23:21:39 +0000
commite3cd735ea6378e5dd7765828f560ed49be845a95 (patch)
tree91101427ae598d9ea6ced7a2e44f0f4f209fe4a9 /clang/lib/CodeGen/CGBuiltin.cpp
parent796ac80b863ed92c3d8bcc296f678ff416afc8a8 (diff)
downloadbcm5719-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.cpp84
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
OpenPOWER on IntegriCloud