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
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a528bff..fd5a6ab 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1474,6 +1474,86 @@
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 @@
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