erik.pilkington created this revision.
erik.pilkington added reviewers: aaron.ballman, rjmccall, eli.friedman.
Herald added subscribers: dexonsmith, jkorous.
Herald added a project: clang.
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.
Without this attribute, its impossible to write `gnu_inline`-style wrappers to
the variadic functions because we don't support `__builtin_va_arg_pack`, and
don't intend to (see https://reviews.llvm.org/D57635).
Thanks for taking a look!
Erik
Repository:
rC Clang
https://reviews.llvm.org/D57918
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/Builtins.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Basic/Builtins.cpp
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/fortify-std-lib.c
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/Sema/fortify-std-lib.c
Index: clang/test/Sema/fortify-std-lib.c
===================================================================
--- /dev/null
+++ clang/test/Sema/fortify-std-lib.c
@@ -0,0 +1,18 @@
+// 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_anyting_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 *, ...);
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -52,6 +52,7 @@
// 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)
Index: clang/test/CodeGen/fortify-std-lib.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fortify-std-lib.c
@@ -0,0 +1,220 @@
+// 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, {{.*}})
+}
+
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6419,6 +6419,31 @@
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_outof_range)
+ << AL << 0 << 3;
+ return;
+ }
+
+ D->addAttr(::new (S.getASTContext()) FortifyStdLibAttr(
+ AL.getLoc(), S.getASTContext(), BOSType, Flag,
+ AL.getAttributeSpellingListIndex()));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -7148,6 +7173,10 @@
case ParsedAttr::AT_ObjCExternallyRetained:
handleObjCExternallyRetainedAttr(S, D, AL);
break;
+
+ case ParsedAttr::AT_FortifyStdLib:
+ handleFortifyStdLib(S, D, AL);
+ break;
}
}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -1487,6 +1487,131 @@
Result.Val.getFloat()));
}
+ if (auto *Attr = FD->getAttr<FortifyStdLibAttr>()) {
+ SmallVector<llvm::Value *, 8> ArgVals;
+ for (const Expr *Arg : E->arguments())
+ ArgVals.push_back(EmitScalarExpr(Arg));
+
+ llvm::Value *Flag = llvm::ConstantInt::get(IntTy, Attr->getFlag());
+ auto emitObjSize = [&]() -> llvm::Value * {
+ return evaluateOrEmitBuiltinObjectSize(E->getArg(0), Attr->getType(),
+ 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.
+ switch (BuiltinID) {
+ case Builtin::BImemcpy:
+ // void *memcpy(void *dst, const void *src, size_t len);
+ // void *__memcpy_chk(void *dst, const void *src, size_t len, size_t);
+ case Builtin::BImemmove:
+ // void *memmove(void *dst, const void *src, size_t len);
+ // void *___memmove_chk(void *dst, const void *src, size_t len, size_t);
+ case Builtin::BImemset:
+ // void *memset(void *b, int c, size_t len);
+ // void *__memset_chk(void *b, int c, size_t len, size_t);
+ ArgVals.push_back(emitObjSize());
+ break;
+
+ case Builtin::BIstpcpy:
+ // char *stpcpy(char *dst, const char *src);
+ // char *__stpcpy_chk(char *dst, const char *src, size_t);
+ case Builtin::BIstrcat:
+ // char *strcat(char *s1, const char *s2);
+ // char *__strcat_chk(char *s1, const char *s2, size_t);
+ case Builtin::BIstrcpy:
+ // char *strcpy(char *dst, const char *src);
+ // char *__strcpy_chk(char *dst, const char *src, size_t);
+ ArgVals.push_back(emitObjSize());
+ break;
+
+ case Builtin::BIstrlcat:
+ // size_t strlcat(char *dst, const char *source, size_t size);
+ // size_t __strlcat_chk(char *dst, const char *source, size_t size,
+ // size_t);
+ case Builtin::BIstrlcpy:
+ // size_t strlcpy(char *dst, const char *source, size_t size);
+ // size_t __strlcpy_chk(char *dst, const char *source, size_t size,
+ // size_t);
+ case Builtin::BIstrncat:
+ // char *strncat(char *s1, const char *s2, size_t n);
+ // char *__strncat_chk(char *s1, const char *s2, size_t n, size_t);
+ case Builtin::BIstrncpy:
+ // char *strncpy(char *dst, const char *src, size_t n);
+ // char *__strncpy_chk(char *dst, const char *src, size_t n, size_t);
+ case Builtin::BIstpncpy:
+ // char *stpncpy(char *dst, const char *src, size_t n);
+ // char *__stpncpy_chk(char *dst, const char *src, size_t n, size_t);
+ ArgVals.push_back(emitObjSize());
+ break;
+
+
+ case Builtin::BIsnprintf:
+ // int snprintf(char *buf, size_t n, const char *fmt, ...);
+ // int __snprintf_chk(char *buf, size_t n, int _flag, size_t _bos,
+ // const char *fmt, ...);
+ case Builtin::BIvsnprintf:
+ // int vsnprintf(char *buf, size_t n, const char *fmt, va_list lst);
+ // int __vsnprintf_chk(char *buf, size_t n, int _flag, size_t _bos,
+ // const char *fmt, va_list lst);
+ ArgVals.insert(ArgVals.begin() + 2, Flag);
+ ArgVals.insert(ArgVals.begin() + 3, emitObjSize());
+ break;
+
+ case Builtin::BIsprintf:
+ // int sprintf(char *buf, const char *fmt, ...);
+ // int __sprintf_chk(char *buf, int _flag, size_t _bos,
+ // const char *fmt, ...)
+ case Builtin::BIvsprintf:
+ // int vsprintf(char *buf, const char *fmt, va_list lst);
+ // int __vsprintf_chk(char *buf, int _flag, size_t _bos, const char *fmt,
+ // va_list lst);
+ ArgVals.insert(ArgVals.begin() + 1, Flag);
+ ArgVals.insert(ArgVals.begin() + 2, emitObjSize());
+ break;
+
+ case Builtin::BIfprintf:
+ // int fprintf(FILE *file, const char *fmt, ...);
+ // int __fprintf_chk(FILE *file, int _flag, const char *fmt, ...);
+ case Builtin::BIvfprintf:
+ // int vfprintf(FILE *file, const char *fmt, va_list lst);
+ // int __vfprintf_chk(FILE *file, int _flag, const char *fmt,
+ // va_list lst);
+ ArgVals.insert(ArgVals.begin() + 1, Flag);
+ break;
+
+ case Builtin::BIprintf:
+ // int fprintf(const char *fmt, ...);
+ // int __fprintf_chk(int _flag, const char *fmt, ...);
+ case Builtin::BIvprintf:
+ // int vprintf(const char *fmt, va_list lst);
+ // int __vprintf_chk(int _flags, const char *fmt, va_list lst);
+ ArgVals.insert(ArgVals.begin(), Flag);
+ 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");
+ llvm::FunctionType *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);
+ }
+
// 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
Index: clang/lib/Basic/Builtins.cpp
===================================================================
--- clang/lib/Basic/Builtins.cpp
+++ clang/lib/Basic/Builtins.cpp
@@ -188,3 +188,28 @@
(!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;
+ }
+}
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4818,6 +4818,8 @@
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">;
Index: clang/include/clang/Basic/Builtins.h
===================================================================
--- clang/include/clang/Basic/Builtins.h
+++ clang/include/clang/Basic/Builtins.h
@@ -242,7 +242,13 @@
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 {
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -965,6 +965,27 @@
}];
}
+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``. 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);
+ }
+ }];
+}
+
def ConvergentDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1567,6 +1567,13 @@
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">];
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits