Author: Alexander Potapenko Date: 2021-08-20T14:01:06+02:00 New Revision: b0391dfc737ede147e128fe877045f61fc5e4905
URL: https://github.com/llvm/llvm-project/commit/b0391dfc737ede147e128fe877045f61fc5e4905 DIFF: https://github.com/llvm/llvm-project/commit/b0391dfc737ede147e128fe877045f61fc5e4905.diff LOG: [clang][Codegen] Introduce the disable_sanitizer_instrumentation attribute The purpose of __attribute__((disable_sanitizer_instrumentation)) is to prevent all kinds of sanitizer instrumentation applied to a certain function, Objective-C method, or global variable. The no_sanitize(...) attribute drops instrumentation checks, but may still insert code preventing false positive reports. In some cases though (e.g. when building Linux kernel with -fsanitize=kernel-memory or -fsanitize=thread) the users may want to avoid any kind of instrumentation. Differential Revision: https://reviews.llvm.org/D108029 Added: clang/test/CodeGen/attr-disable-sanitizer-instrumentation.c Modified: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/test/Misc/pragma-attribute-supported-attributes-list.test llvm/docs/BitCodeFormat.rst llvm/docs/LangRef.rst llvm/include/llvm/AsmParser/LLToken.h llvm/include/llvm/Bitcode/LLVMBitCodes.h llvm/include/llvm/IR/Attributes.td llvm/lib/AsmParser/LLLexer.cpp llvm/lib/Bitcode/Reader/BitcodeReader.cpp llvm/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/lib/Transforms/Utils/CodeExtractor.cpp llvm/test/Bitcode/attributes.ll llvm/test/Bitcode/compatibility.ll Removed: ################################################################################ diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 13d8c15001c92..f9ae1b8d86281 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2948,6 +2948,13 @@ def NoSanitizeSpecific : InheritableAttr { let ASTNode = 0; } +def DisableSanitizerInstrumentation : InheritableAttr { + let Spellings = [Clang<"disable_sanitizer_instrumentation">]; + let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar]>; + let Documentation = [DisableSanitizerInstrumentationDocs]; + let SimpleHandler = 1; +} + def CFICanonicalJumpTable : InheritableAttr { let Spellings = [Clang<"cfi_canonical_jump_table">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a1206347ae454..5c63c8440ad80 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2602,6 +2602,18 @@ full list of supported sanitizer flags. }]; } +def DisableSanitizerInstrumentationDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use the ``disable_sanitizer_instrumentation`` attribute on a function, +Objective-C method, or global variable, to specify that no sanitizer +instrumentation should be applied. + +This is not the same as ``__attribute__((no_sanitize(...)))``, which depending +on the tool may still insert instrumentation to prevent false positive reports. + }]; +} + def NoSanitizeAddressDocs : Documentation { let Category = DocCatFunction; // This function has multiple distinct spellings, and so it requires a custom diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index dca42045325df..e3a66318c086c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -381,6 +381,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { "__cyg_profile_func_exit"); } + if (ShouldSkipSanitizerInstrumentation()) + CurFn->addFnAttr(llvm::Attribute::DisableSanitizerInstrumentation); + // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) DI->EmitFunctionEnd(Builder, CurFn); @@ -519,6 +522,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() { return true; } +bool CodeGenFunction::ShouldSkipSanitizerInstrumentation() { + if (!CurFuncDecl) + return false; + return CurFuncDecl->hasAttr<DisableSanitizerInstrumentationAttr>(); +} + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool CodeGenFunction::ShouldXRayInstrumentFunction() const { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 0baa45e6b9f27..f74bff91f007c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2286,6 +2286,10 @@ class CodeGenFunction : public CodeGenTypeCache { /// instrumented with __cyg_profile_func_* calls bool ShouldInstrumentFunction(); + /// ShouldSkipSanitizerInstrumentation - Return true if the current function + /// should not be instrumented with sanitizers. + bool ShouldSkipSanitizerInstrumentation(); + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; diff --git a/clang/test/CodeGen/attr-disable-sanitizer-instrumentation.c b/clang/test/CodeGen/attr-disable-sanitizer-instrumentation.c new file mode 100644 index 0000000000000..74ebe1b548807 --- /dev/null +++ b/clang/test/CodeGen/attr-disable-sanitizer-instrumentation.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -debug-info-kind=limited %s -emit-llvm -o - | FileCheck %s + +void t1() __attribute__((disable_sanitizer_instrumentation)) { +} +// CHECK: disable_sanitizer_instrumentation +// CHECK-NEXT: void @t1 + +// CHECK-NOT: disable_sanitizer_instrumentation +// CHECK: void @t2 +void t2() { +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index bf960ca046821..88488d210945f 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -57,6 +57,7 @@ // CHECK-NEXT: DLLExport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface) // CHECK-NEXT: DLLImport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface) // CHECK-NEXT: Destructor (SubjectMatchRule_function) +// CHECK-NEXT: DisableSanitizerInstrumentation (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global) // CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: EnableIf (SubjectMatchRule_function) // CHECK-NEXT: EnforceTCB (SubjectMatchRule_function) diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst index fcc10d5efe5b7..32f87fe719f88 100644 --- a/llvm/docs/BitCodeFormat.rst +++ b/llvm/docs/BitCodeFormat.rst @@ -1075,6 +1075,8 @@ The integer codes are mapped to well-known attributes as follows. * code 74: ``vscale_range(<Min>[, <Max>])`` * code 75: ``swiftasync`` * code 76: ``nosanitize_coverage`` +* code 77: ``elementtype`` +* code 78: ``disable_sanitizer_instrumentation`` .. note:: The ``allocsize`` attribute has a special encoding for its arguments. Its two diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index dd7ea4c58b755..543783a8a90d2 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1582,6 +1582,19 @@ example: can prove that the function does not execute any convergent operations. Similarly, the optimizer may remove ``convergent`` on calls/invokes when it can prove that the call/invoke cannot call a convergent function. +``disable_sanitizer_instrumentation`` + When instrumenting code with sanitizers, it can be important to skip certain + functions to ensure no instrumentation is applied to them. + + This attribute is not always similar to absent ``sanitize_<name>`` + attributes: depending on the specific sanitizer, code can be inserted into + functions regardless of the ``sanitize_<name>`` attribute to prevent false + positive reports. + + ``disable_sanitizer_instrumentation`` disables all kinds of instrumentation, + taking precedence over the ``sanitize_<name>`` attributes and other compiler + flags. + ``"frame-pointer"`` This attribute tells the code generator whether the function should keep the frame pointer. The code generator may emit the frame pointer diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index e38b7fd0f3ea9..bc35f6381c0db 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -190,6 +190,7 @@ enum Kind { kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_disable_sanitizer_instrumentation, kw_elementtype, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 28870afb2fcb3..04eb2739cbd5a 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -671,6 +671,7 @@ enum AttributeKindCodes { ATTR_KIND_SWIFT_ASYNC = 75, ATTR_KIND_NO_SANITIZE_COVERAGE = 76, ATTR_KIND_ELEMENTTYPE = 77, + ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION = 78, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 99b474161df7a..de25b51a62927 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -86,6 +86,9 @@ def Dereferenceable : IntAttr<"dereferenceable", [ParamAttr, RetAttr]>; def DereferenceableOrNull : IntAttr<"dereferenceable_or_null", [ParamAttr, RetAttr]>; +/// Do not instrument function with sanitizers. +def DisableSanitizerInstrumentation: EnumAttr<"disable_sanitizer_instrumentation", [FnAttr]>; + /// Provide pointer element type to intrinsic. def ElementType : TypeAttr<"elementtype", [ParamAttr]>; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 4f72c6f9921a9..bee3d947de930 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -643,6 +643,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(disable_sanitizer_instrumentation); KEYWORD(elementtype); KEYWORD(inaccessiblememonly); KEYWORD(inaccessiblemem_or_argmemonly); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index eb6a7f39b9341..49ba562d8ab7b 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1388,6 +1388,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; + case bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION: + return Attribute::DisableSanitizerInstrumentation; case bitc::ATTR_KIND_ELEMENTTYPE: return Attribute::ElementType; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index c5d8c553a340a..1d578a9674296 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -626,6 +626,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_IN_ALLOCA; case Attribute::Cold: return bitc::ATTR_KIND_COLD; + case Attribute::DisableSanitizerInstrumentation: + return bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION; case Attribute::Hot: return bitc::ATTR_KIND_HOT; case Attribute::ElementType: diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index ccd62b7bbd41e..0411c9bfab5d7 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -943,6 +943,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, // Those attributes should be safe to propagate to the extracted function. case Attribute::AlwaysInline: case Attribute::Cold: + case Attribute::DisableSanitizerInstrumentation: case Attribute::Hot: case Attribute::NoRecurse: case Attribute::InlineHint: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index 6ba8ce2854d6b..4ec827fe63e0c 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -472,6 +472,12 @@ define void @f79() { ret void } +; CHECK: define void @f80() #50 +define void @f80() disable_sanitizer_instrumentation +{ + ret void; +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -522,4 +528,5 @@ define void @f79() { ; CHECK: attributes #47 = { vscale_range(1,0) } ; CHECK: attributes #48 = { nosanitize_coverage } ; CHECK: attributes #49 = { noprofile } +; CHECK: attributes #50 = { disable_sanitizer_instrumentation } ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin } diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index c2bfb3a3523d3..2281938c6d834 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -1510,7 +1510,7 @@ exit: ; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2> call void @f.nobuiltin() builtin - ; CHECK: call void @f.nobuiltin() #45 + ; CHECK: call void @f.nobuiltin() #46 call fastcc noalias i32* @f.noalias() noinline ; CHECK: call fastcc noalias i32* @f.noalias() #12 @@ -1907,6 +1907,9 @@ define void @instructions.strictfp() strictfp { declare void @f.nosanitize_coverage() nosanitize_coverage ; CHECK: declare void @f.nosanitize_coverage() #44 +declare void @f.disable_sanitizer_instrumentation() disable_sanitizer_instrumentation +; CHECK: declare void @f.disable_sanitizer_instrumentation() #45 + ; immarg attribute declare void @llvm.test.immarg.intrinsic(i32 immarg) ; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg) @@ -1965,7 +1968,8 @@ declare void @byval_named_type(%named_type* byval(%named_type)) ; CHECK: attributes #42 = { speculatable } ; CHECK: attributes #43 = { strictfp } ; CHECK: attributes #44 = { nosanitize_coverage } -; CHECK: attributes #45 = { builtin } +; CHECK: attributes #45 = { disable_sanitizer_instrumentation } +; CHECK: attributes #46 = { builtin } ;; Metadata _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits