let Documentation = [PassObjectSizeDocs];
}
-def FortifyStdLib : InheritableAttr {
- let Spellings = [Clang<"fortify_stdlib">];
- let Args = [IntArgument<"Type">, IntArgument<"Flag">];
- let Subjects = SubjectList<[Function]>;
- let Documentation = [FortifyStdLibDocs];
-}
-
// Nullability type attributes.
def TypeNonNull : TypeAttr {
let Spellings = [Keyword<"_Nonnull">];
}];
}
-def FortifyStdLibDocs : Documentation {
- let Category = DocCatFunction;
- let Content = [{
-The ``fortify_stdlib`` attribute applies to declarations of C stdlib functions
-(memcpy, sprintf, ...), and causes clang to emit calls to their fortified
-variants with ``__builtin_object_size``. This attribute is intended for use
-within standard C library implementations and should not generally be used for
-user applications. For instance:
-
-.. code-block:: c
-
- __attribute__((fortify_stdlib(0, 0)))
- int sprintf(char *buf, const char *fmt, ...);
-
- int main() {
- char buf[5];
- sprintf(buf, "%f", 42.0);
- // Clang generates code equivalent to:
- // __sprintf_chk(buf, 0, __builtin_object_size(0), "%f", 42.0);
- }
-
-The first argument to the attribute is the integer `type` argument passed to
-`__builtin_object_size` (you can read more about `__builtin_object_size`
-`here <https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Object-Size-Checking.html>`_),
-The second argument to this attribute is the flag that the fortified format
-functions accept.
-
-Only a specific set of standard library functions are supported:
- - memcpy, memmove, memset
- - stpcpy, strcat, strcpy
- - strlcat, strlcpy
- - strncat, strncpy, stpncpy
- - snprintf, vsnprintf, sprintf, vsprintf
- - fprintf, vfprintf, printf, vprintf
-}];
-}
-
def ConvergentDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
const char *Fmt) const;
};
-/// For a given BuiltinID, return the ID of the fortified variant function. For
-/// instance, if Builtin::BIsprintf is passed, this function will return
-/// Builtin::BI__builtin___sprintf_chk. If BuiltinID doesn't have a fortified
-/// variant, 0 is returned.
-unsigned getFortifiedVariantFunction(unsigned BuiltinID);
-
-} // end namespace Builtin
+}
/// Kinds of BuiltinTemplateDecl.
enum BuiltinTemplateKind : int {
def ext_forward_ref_enum_def : Extension<
"redeclaration of already-defined enum %0 is a GNU extension">,
InGroup<GNURedeclaredEnum>;
-def err_fortify_std_lib_bad_decl : Error<
- "'fortify_stdlib' attribute applied to an unknown function">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
(!hasReferenceArgsOrResult(ID) &&
!hasCustomTypechecking(ID));
}
-
-unsigned Builtin::getFortifiedVariantFunction(unsigned BuiltinID) {
- switch (BuiltinID) {
- case Builtin::BImemcpy: return Builtin::BI__builtin___memcpy_chk;
- case Builtin::BImemmove: return Builtin::BI__builtin___memmove_chk;
- case Builtin::BImemset: return Builtin::BI__builtin___memset_chk;
- case Builtin::BIstpcpy: return Builtin::BI__builtin___stpcpy_chk;
- case Builtin::BIstrcat: return Builtin::BI__builtin___strcat_chk;
- case Builtin::BIstrcpy: return Builtin::BI__builtin___strcpy_chk;
- case Builtin::BIstrlcat: return Builtin::BI__builtin___strlcat_chk;
- case Builtin::BIstrlcpy: return Builtin::BI__builtin___strlcpy_chk;
- case Builtin::BIstrncat: return Builtin::BI__builtin___strncat_chk;
- case Builtin::BIstrncpy: return Builtin::BI__builtin___strncpy_chk;
- case Builtin::BIstpncpy: return Builtin::BI__builtin___stpncpy_chk;
- case Builtin::BIsnprintf: return Builtin::BI__builtin___snprintf_chk;
- case Builtin::BIvsnprintf: return Builtin::BI__builtin___vsnprintf_chk;
- case Builtin::BIsprintf: return Builtin::BI__builtin___sprintf_chk;
- case Builtin::BIvsprintf: return Builtin::BI__builtin___vsprintf_chk;
- case Builtin::BIfprintf: return Builtin::BI__builtin___fprintf_chk;
- case Builtin::BIvfprintf: return Builtin::BI__builtin___vfprintf_chk;
- case Builtin::BIprintf: return Builtin::BI__builtin___printf_chk;
- case Builtin::BIvprintf: return Builtin::BI__builtin___vprintf_chk;
- default: return 0;
- }
-}
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) {
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
RValue EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const CallExpr *E, ReturnValueSlot ReturnValue);
- RValue emitFortifiedStdLibCall(CodeGenFunction &CGF, const CallExpr *CE,
- unsigned BuiltinID, unsigned BOSType,
- unsigned Flag);
-
RValue emitRotate(const CallExpr *E, bool IsRotateRight);
/// Emit IR for __builtin_os_log_format.
handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
}
-static void handleFortifyStdLib(Sema &S, Decl *D, const ParsedAttr &AL) {
- auto *FD = cast<FunctionDecl>(D);
- unsigned VariantID = Builtin::getFortifiedVariantFunction(FD->getBuiltinID());
- if (VariantID == 0) {
- S.Diag(D->getLocation(), diag::err_fortify_std_lib_bad_decl);
- return;
- }
-
- uint32_t BOSType, Flag;
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), BOSType, 0, true) ||
- !checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Flag, 1, true))
- return;
-
- if (BOSType > 3) {
- S.Diag(AL.getArgAsExpr(0)->getBeginLoc(),
- diag::err_attribute_argument_out_of_range)
- << AL << 0 << 3;
- return;
- }
-
- D->addAttr(::new (S.getASTContext()) FortifyStdLibAttr(
- AL.getLoc(), S.getASTContext(), BOSType, Flag,
- AL.getAttributeSpellingListIndex()));
-}
-
static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Check that the return type is a `typedef int kern_return_t` or a typedef
// around it, because otherwise MIG convention checks make no sense.
handleObjCExternallyRetainedAttr(S, D, AL);
break;
- case ParsedAttr::AT_FortifyStdLib:
- handleFortifyStdLib(S, D, AL);
- break;
-
case ParsedAttr::AT_MIGServerRoutine:
handleMIGServerRoutineAttr(S, D, AL);
break;
+++ /dev/null
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -O0 -disable-llvm-passes -o - -Wno-format-security | FileCheck %s
-// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -O0 -disable-llvm-passes -o - -Wno-format-security | FileCheck %s
-
-#ifdef __cplusplus
-#define EXTERN extern "C"
-#else
-#define EXTERN
-#endif
-
-#define FSL(x,y) __attribute__((fortify_stdlib(x,y)))
-typedef unsigned long size_t;
-
-FSL(0, 0) EXTERN
-void *memcpy(void *dst, const void *src, size_t sz);
-
-EXTERN
-void call_memcpy(void *dst, const void *src, size_t sz) {
- memcpy(dst, src, sz);
- // CHECK-LABEL: define void @call_memcpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__memcpy_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-void *memmove(void *dst, const void *src, size_t sz);
-
-EXTERN
-void call_memmove(void *dst, const void *src, size_t sz) {
- memmove(dst, src, sz);
- // CHECK-LABEL: define void @call_memmove
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__memmove_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-void *memset(void *dst, int c, size_t sz);
-
-EXTERN
-void call_memset(void *dst, int c, size_t sz) {
- memset(dst, c, sz);
- // CHECK-LABEL: define void @call_memset
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__memset_chk(i8* {{.*}}, i32 {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *stpcpy(char* dst, const char *src);
-
-EXTERN
-void call_stpcpy(char *dst, const char *src) {
- stpcpy(dst, src);
- // CHECK-LABEL: define void @call_stpcpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__stpcpy_chk(i8* {{.*}}, i8* {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *strcat(char* dst, const char *src);
-
-EXTERN
-void call_strcat(char *dst, const char *src) {
- strcat(dst, src);
- // CHECK-LABEL: define void @call_strcat
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__strcat_chk(i8* {{.*}}, i8* {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *strcpy(char* dst, const char *src);
-
-EXTERN
-void call_strcpy(char *dst, const char *src) {
- strcpy(dst, src);
- // CHECK-LABEL: define void @call_strcpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__strcpy_chk(i8* {{.*}}, i8* {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-size_t strlcat(char* dst, const char *src, size_t len);
-
-EXTERN
-void call_strlcat(char *dst, const char *src, size_t len) {
- strlcat(dst, src, len);
- // CHECK-LABEL: define void @call_strlcat
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i64 @__strlcat_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-size_t strlcpy(char* dst, const char *src, size_t len);
-
-EXTERN
-void call_strlcpy(char *dst, const char *src, size_t len) {
- strlcpy(dst, src, len);
- // CHECK-LABEL: define void @call_strlcpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i64 @__strlcpy_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *strncat(char* dst, const char *src, size_t len);
-
-EXTERN
-void call_strncat(char *dst, const char *src, size_t len) {
- strncat(dst, src, len);
- // CHECK-LABEL: define void @call_strncat
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__strncat_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *strncpy(char* dst, const char *src, size_t len);
-
-EXTERN
-void call_strncpy(char *dst, const char *src, size_t len) {
- strncpy(dst, src, len);
- // CHECK-LABEL: define void @call_strncpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__strncpy_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-char *stpncpy(char* dst, const char *src, size_t len);
-
-EXTERN
-void call_stpncpy(char *dst, const char *src, size_t len) {
- stpncpy(dst, src, len);
- // CHECK-LABEL: define void @call_stpncpy
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i8* @__stpncpy_chk(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i64 [[REG]])
-}
-
-FSL(0, 0) EXTERN
-int snprintf(char *buf, size_t n, const char *fmt, ...);
-
-EXTERN
-void call_snprintf(char *buf, size_t n, const char *fmt) {
- snprintf(buf, n, fmt);
- // CHECK-LABEL: define void @call_snprintf
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk(i8* {{.*}}, i64 {{.*}}, i32 0, i64 [[REG]]
-}
-
-FSL(0, 0) EXTERN
-int vsnprintf(char *buf, size_t n, const char *fmt, __builtin_va_list lst);
-
-EXTERN
-void call_vsnprintf(char *buf, size_t n, const char *fmt, __builtin_va_list lst) {
- vsnprintf(buf, n, fmt, lst);
- // CHECK-LABEL: define void @call_vsnprintf
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i32 @__vsnprintf_chk(i8* {{.*}}, i64 {{.*}}, i32 0, i64 [[REG]]
-}
-
-FSL(0,0) EXTERN
-int sprintf(char *buf, const char *fmt, ...);
-
-void call_sprintf(char *buf, const char* fmt) {
- sprintf(buf, fmt);
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* {{.*}}, i32 0, i64 [[REG]]
- sprintf(buf, fmt, 1, 2, 3);
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* {{.*}}, i32 0, i64 [[REG]], i8* {{.*}}, i32 1, i32 2, i32 3)
-}
-
-FSL(0, 0) EXTERN
-int vsprintf(char *buf, const char *fmt, __builtin_va_list lst);
-
-EXTERN
-void call_vsprintf(char *buf, const char *fmt, __builtin_va_list lst) {
- vsprintf(buf, fmt, lst);
- // CHECK-LABEL: define void @call_vsprintf
- // CHECK: [[REG:%[0-9]+]] = call i64 @llvm.objectsize.i64.p0i8(i8*{{.*}}, i1 false, i1 true, i1 false)
- // CHECK: call i32 @__vsprintf_chk(i8* {{.*}}, i32 0, i64 [[REG]]
-}
-
-typedef struct {} FILE;
-
-FSL(0, 0) EXTERN
-int fprintf(FILE *file, const char *fmt, ...);
-
-EXTERN
-void call_fprintf(FILE *file, const char *fmt) {
- fprintf(file, fmt);
- // CHECK-LABEL: define void @call_fprintf
- // CHECK: call i32 ({{.*}}*, i32, i8*, ...) @__fprintf_chk({{.*}}, i32 0, i8* {{.*}})
-}
-
-FSL(0, 0) EXTERN
-int vfprintf(FILE *file, const char *fmt, __builtin_va_list lst);
-
-EXTERN
-void call_vfprintf(FILE *file, const char *fmt, __builtin_va_list lst) {
- vfprintf(file, fmt, lst);
- // CHECK-LABEL: define void @call_vfprintf
- // CHECK: call i32 @__vfprintf_chk({{.*}}, i32 0, i8* {{.*}}, {{.*}})
-}
-
-FSL(0, 0) EXTERN
-int printf(const char *fmt, ...);
-
-EXTERN
-void call_printf(const char *fmt) {
- printf(fmt);
- // CHECK-LABEL: define void @call_printf
- // CHECK: call i32 (i32, i8*, ...) @__printf_chk(i32 0, i8* {{.*}})
-}
-
-FSL(0, 0) EXTERN
-int vprintf(const char *fmt, __builtin_va_list lst);
-
-EXTERN
-void call_vprintf(const char *fmt, __builtin_va_list lst) {
- vprintf(fmt, lst);
- // CHECK-LABEL: define void @call_vprintf
- // CHECK: call i32 @__vprintf_chk(i32 0, {{.*}})
-}
-
// CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
// CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
// CHECK-NEXT: Flatten (SubjectMatchRule_function)
-// CHECK-NEXT: FortifyStdLib (SubjectMatchRule_function)
// CHECK-NEXT: GNUInline (SubjectMatchRule_function)
// CHECK-NEXT: Hot (SubjectMatchRule_function)
// CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
+++ /dev/null
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -fsyntax-only %s -verify
-
-typedef unsigned long size_t;
-
-__attribute__((fortify_stdlib(0, 0)))
-int not_anything_special(); // expected-error {{'fortify_stdlib' attribute applied to an unknown function}}
-
-__attribute__((fortify_stdlib(4, 0))) // expected-error {{'fortify_stdlib' attribute requires integer constant between 0 and 3 inclusive}}
-int sprintf(char *, const char *, ...);
-
-__attribute__((fortify_stdlib())) // expected-error {{'fortify_stdlib' attribute requires exactly 2 arguments}}
-int sprintf(char *, const char *, ...);
-
-__attribute__((fortify_stdlib(1, 2, 3))) // expected-error {{'fortify_stdlib' attribute requires exactly 2 arguments}}
-int sprintf(char *, const char *, ...);
-
-__attribute__((fortify_stdlib(-1, 2))) // expected-error {{'fortify_stdlib' attribute requires a non-negative integral compile time constant expression}}
-int sprintf(char *, const char *, ...);