mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[SanitizeCoverage] Add support for NoSanitizeCoverage function attribute
We really ought to support no_sanitize("coverage") in line with other sanitizers. This came up again in discussions on the Linux-kernel mailing lists, because we currently do workarounds using objtool to remove coverage instrumentation. Since that support is only on x86, to continue support coverage instrumentation on other architectures, we must support selectively disabling coverage instrumentation via function attributes. Unfortunately, for SanitizeCoverage, it has not been implemented as a sanitizer via fsanitize= and associated options in Sanitizers.def, but rolls its own option fsanitize-coverage. This meant that we never got "automatic" no_sanitize attribute support. Implement no_sanitize attribute support by special-casing the string "coverage" in the NoSanitizeAttr implementation. To keep the feature as unintrusive to existing IR generation as possible, define a new negative function attribute NoSanitizeCoverage to propagate the information through to the instrumentation pass. Fixes: https://bugs.llvm.org/show_bug.cgi?id=49035 Reviewed By: vitalybuka, morehouse Differential Revision: https://reviews.llvm.org/D102772
This commit is contained in:
parent
91c3ce1475
commit
b835b9cf36
@ -69,6 +69,7 @@ func TestAttributes(t *testing.T) {
|
|||||||
"noredzone",
|
"noredzone",
|
||||||
"noreturn",
|
"noreturn",
|
||||||
"nounwind",
|
"nounwind",
|
||||||
|
"nosanitize_coverage",
|
||||||
"optnone",
|
"optnone",
|
||||||
"optsize",
|
"optsize",
|
||||||
"readnone",
|
"readnone",
|
||||||
|
@ -1073,6 +1073,8 @@ The integer codes are mapped to well-known attributes as follows.
|
|||||||
* code 69: ``byref``
|
* code 69: ``byref``
|
||||||
* code 70: ``mustprogress``
|
* code 70: ``mustprogress``
|
||||||
* code 74: ``vscale_range(<Min>[, <Max>])``
|
* code 74: ``vscale_range(<Min>[, <Max>])``
|
||||||
|
* code 75: ``swiftasync``
|
||||||
|
* code 76: ``nosanitize_coverage``
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The ``allocsize`` attribute has a special encoding for its arguments. Its two
|
The ``allocsize`` attribute has a special encoding for its arguments. Its two
|
||||||
|
@ -1691,6 +1691,9 @@ example:
|
|||||||
trap or generate asynchronous exceptions. Exception handling schemes
|
trap or generate asynchronous exceptions. Exception handling schemes
|
||||||
that are recognized by LLVM to handle asynchronous exceptions, such
|
that are recognized by LLVM to handle asynchronous exceptions, such
|
||||||
as SEH, will still provide their implementation defined semantics.
|
as SEH, will still provide their implementation defined semantics.
|
||||||
|
``nosanitize_coverage``
|
||||||
|
This attribute indicates that SanitizerCoverage instrumentation is disabled
|
||||||
|
for this function.
|
||||||
``null_pointer_is_valid``
|
``null_pointer_is_valid``
|
||||||
If ``null_pointer_is_valid`` is set, then the ``null`` address
|
If ``null_pointer_is_valid`` is set, then the ``null`` address
|
||||||
in address-space 0 is considered to be a valid address for memory loads and
|
in address-space 0 is considered to be a valid address for memory loads and
|
||||||
|
@ -217,6 +217,7 @@ enum Kind {
|
|||||||
kw_nosync,
|
kw_nosync,
|
||||||
kw_nocf_check,
|
kw_nocf_check,
|
||||||
kw_nounwind,
|
kw_nounwind,
|
||||||
|
kw_nosanitize_coverage,
|
||||||
kw_null_pointer_is_valid,
|
kw_null_pointer_is_valid,
|
||||||
kw_optforfuzzing,
|
kw_optforfuzzing,
|
||||||
kw_optnone,
|
kw_optnone,
|
||||||
|
@ -666,6 +666,7 @@ enum AttributeKindCodes {
|
|||||||
ATTR_KIND_NO_PROFILE = 73,
|
ATTR_KIND_NO_PROFILE = 73,
|
||||||
ATTR_KIND_VSCALE_RANGE = 74,
|
ATTR_KIND_VSCALE_RANGE = 74,
|
||||||
ATTR_KIND_SWIFT_ASYNC = 75,
|
ATTR_KIND_SWIFT_ASYNC = 75,
|
||||||
|
ATTR_KIND_NO_SANITIZE_COVERAGE = 76,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ComdatSelectionKindCodes {
|
enum ComdatSelectionKindCodes {
|
||||||
|
@ -154,6 +154,9 @@ def NoProfile : EnumAttr<"noprofile">;
|
|||||||
/// Function doesn't unwind stack.
|
/// Function doesn't unwind stack.
|
||||||
def NoUnwind : EnumAttr<"nounwind">;
|
def NoUnwind : EnumAttr<"nounwind">;
|
||||||
|
|
||||||
|
/// No SanitizeCoverage instrumentation.
|
||||||
|
def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage">;
|
||||||
|
|
||||||
/// Null pointer in address space zero is valid.
|
/// Null pointer in address space zero is valid.
|
||||||
def NullPointerIsValid : EnumAttr<"null_pointer_is_valid">;
|
def NullPointerIsValid : EnumAttr<"null_pointer_is_valid">;
|
||||||
|
|
||||||
|
@ -671,6 +671,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
|||||||
KEYWORD(nocf_check);
|
KEYWORD(nocf_check);
|
||||||
KEYWORD(noundef);
|
KEYWORD(noundef);
|
||||||
KEYWORD(nounwind);
|
KEYWORD(nounwind);
|
||||||
|
KEYWORD(nosanitize_coverage);
|
||||||
KEYWORD(null_pointer_is_valid);
|
KEYWORD(null_pointer_is_valid);
|
||||||
KEYWORD(optforfuzzing);
|
KEYWORD(optforfuzzing);
|
||||||
KEYWORD(optnone);
|
KEYWORD(optnone);
|
||||||
|
@ -1398,6 +1398,9 @@ bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
|
|||||||
case lltok::kw_noprofile: B.addAttribute(Attribute::NoProfile); break;
|
case lltok::kw_noprofile: B.addAttribute(Attribute::NoProfile); break;
|
||||||
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
|
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
|
||||||
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
|
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
|
||||||
|
case lltok::kw_nosanitize_coverage:
|
||||||
|
B.addAttribute(Attribute::NoSanitizeCoverage);
|
||||||
|
break;
|
||||||
case lltok::kw_null_pointer_is_valid:
|
case lltok::kw_null_pointer_is_valid:
|
||||||
B.addAttribute(Attribute::NullPointerIsValid); break;
|
B.addAttribute(Attribute::NullPointerIsValid); break;
|
||||||
case lltok::kw_optforfuzzing:
|
case lltok::kw_optforfuzzing:
|
||||||
@ -1825,6 +1828,7 @@ bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
|
|||||||
case lltok::kw_noreturn:
|
case lltok::kw_noreturn:
|
||||||
case lltok::kw_nocf_check:
|
case lltok::kw_nocf_check:
|
||||||
case lltok::kw_nounwind:
|
case lltok::kw_nounwind:
|
||||||
|
case lltok::kw_nosanitize_coverage:
|
||||||
case lltok::kw_optforfuzzing:
|
case lltok::kw_optforfuzzing:
|
||||||
case lltok::kw_optnone:
|
case lltok::kw_optnone:
|
||||||
case lltok::kw_optsize:
|
case lltok::kw_optsize:
|
||||||
@ -1936,6 +1940,7 @@ bool LLParser::parseOptionalReturnAttrs(AttrBuilder &B) {
|
|||||||
case lltok::kw_noreturn:
|
case lltok::kw_noreturn:
|
||||||
case lltok::kw_nocf_check:
|
case lltok::kw_nocf_check:
|
||||||
case lltok::kw_nounwind:
|
case lltok::kw_nounwind:
|
||||||
|
case lltok::kw_nosanitize_coverage:
|
||||||
case lltok::kw_optforfuzzing:
|
case lltok::kw_optforfuzzing:
|
||||||
case lltok::kw_optnone:
|
case lltok::kw_optnone:
|
||||||
case lltok::kw_optsize:
|
case lltok::kw_optsize:
|
||||||
|
@ -1474,6 +1474,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
|
|||||||
return Attribute::NoCfCheck;
|
return Attribute::NoCfCheck;
|
||||||
case bitc::ATTR_KIND_NO_UNWIND:
|
case bitc::ATTR_KIND_NO_UNWIND:
|
||||||
return Attribute::NoUnwind;
|
return Attribute::NoUnwind;
|
||||||
|
case bitc::ATTR_KIND_NO_SANITIZE_COVERAGE:
|
||||||
|
return Attribute::NoSanitizeCoverage;
|
||||||
case bitc::ATTR_KIND_NULL_POINTER_IS_VALID:
|
case bitc::ATTR_KIND_NULL_POINTER_IS_VALID:
|
||||||
return Attribute::NullPointerIsValid;
|
return Attribute::NullPointerIsValid;
|
||||||
case bitc::ATTR_KIND_OPT_FOR_FUZZING:
|
case bitc::ATTR_KIND_OPT_FOR_FUZZING:
|
||||||
|
@ -686,6 +686,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
|||||||
return bitc::ATTR_KIND_NO_PROFILE;
|
return bitc::ATTR_KIND_NO_PROFILE;
|
||||||
case Attribute::NoUnwind:
|
case Attribute::NoUnwind:
|
||||||
return bitc::ATTR_KIND_NO_UNWIND;
|
return bitc::ATTR_KIND_NO_UNWIND;
|
||||||
|
case Attribute::NoSanitizeCoverage:
|
||||||
|
return bitc::ATTR_KIND_NO_SANITIZE_COVERAGE;
|
||||||
case Attribute::NullPointerIsValid:
|
case Attribute::NullPointerIsValid:
|
||||||
return bitc::ATTR_KIND_NULL_POINTER_IS_VALID;
|
return bitc::ATTR_KIND_NULL_POINTER_IS_VALID;
|
||||||
case Attribute::OptForFuzzing:
|
case Attribute::OptForFuzzing:
|
||||||
|
@ -442,6 +442,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
|||||||
return "noprofile";
|
return "noprofile";
|
||||||
if (hasAttribute(Attribute::NoUnwind))
|
if (hasAttribute(Attribute::NoUnwind))
|
||||||
return "nounwind";
|
return "nounwind";
|
||||||
|
if (hasAttribute(Attribute::NoSanitizeCoverage))
|
||||||
|
return "nosanitize_coverage";
|
||||||
if (hasAttribute(Attribute::OptForFuzzing))
|
if (hasAttribute(Attribute::OptForFuzzing))
|
||||||
return "optforfuzzing";
|
return "optforfuzzing";
|
||||||
if (hasAttribute(Attribute::OptimizeNone))
|
if (hasAttribute(Attribute::OptimizeNone))
|
||||||
|
@ -1661,6 +1661,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
|
|||||||
case Attribute::NoCfCheck:
|
case Attribute::NoCfCheck:
|
||||||
case Attribute::NoUnwind:
|
case Attribute::NoUnwind:
|
||||||
case Attribute::NoInline:
|
case Attribute::NoInline:
|
||||||
|
case Attribute::NoSanitizeCoverage:
|
||||||
case Attribute::AlwaysInline:
|
case Attribute::AlwaysInline:
|
||||||
case Attribute::OptimizeForSize:
|
case Attribute::OptimizeForSize:
|
||||||
case Attribute::StackProtect:
|
case Attribute::StackProtect:
|
||||||
|
@ -53,6 +53,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) {
|
|||||||
.Case("nocf_check", Attribute::NoCfCheck)
|
.Case("nocf_check", Attribute::NoCfCheck)
|
||||||
.Case("norecurse", Attribute::NoRecurse)
|
.Case("norecurse", Attribute::NoRecurse)
|
||||||
.Case("nounwind", Attribute::NoUnwind)
|
.Case("nounwind", Attribute::NoUnwind)
|
||||||
|
.Case("nosanitize_coverage", Attribute::NoSanitizeCoverage)
|
||||||
.Case("optforfuzzing", Attribute::OptForFuzzing)
|
.Case("optforfuzzing", Attribute::OptForFuzzing)
|
||||||
.Case("optnone", Attribute::OptimizeNone)
|
.Case("optnone", Attribute::OptimizeNone)
|
||||||
.Case("optsize", Attribute::OptimizeForSize)
|
.Case("optsize", Attribute::OptimizeForSize)
|
||||||
|
@ -621,6 +621,8 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
|||||||
return;
|
return;
|
||||||
if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
|
if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
|
||||||
return;
|
return;
|
||||||
|
if (F.hasFnAttribute(Attribute::NoSanitizeCoverage))
|
||||||
|
return;
|
||||||
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
|
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
|
||||||
SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
|
SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
|
||||||
SmallVector<Instruction *, 8> IndirCalls;
|
SmallVector<Instruction *, 8> IndirCalls;
|
||||||
|
@ -954,6 +954,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
|
|||||||
case Attribute::NonLazyBind:
|
case Attribute::NonLazyBind:
|
||||||
case Attribute::NoRedZone:
|
case Attribute::NoRedZone:
|
||||||
case Attribute::NoUnwind:
|
case Attribute::NoUnwind:
|
||||||
|
case Attribute::NoSanitizeCoverage:
|
||||||
case Attribute::NullPointerIsValid:
|
case Attribute::NullPointerIsValid:
|
||||||
case Attribute::OptForFuzzing:
|
case Attribute::OptForFuzzing:
|
||||||
case Attribute::OptimizeNone:
|
case Attribute::OptimizeNone:
|
||||||
|
@ -453,6 +453,12 @@ define void @f76(i8* swiftasync %0)
|
|||||||
ret void;
|
ret void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; CHECK: define void @f77() #48
|
||||||
|
define void @f77() nosanitize_coverage
|
||||||
|
{
|
||||||
|
ret void;
|
||||||
|
}
|
||||||
|
|
||||||
; CHECK: attributes #0 = { noreturn }
|
; CHECK: attributes #0 = { noreturn }
|
||||||
; CHECK: attributes #1 = { nounwind }
|
; CHECK: attributes #1 = { nounwind }
|
||||||
; CHECK: attributes #2 = { readnone }
|
; CHECK: attributes #2 = { readnone }
|
||||||
@ -501,4 +507,5 @@ define void @f76(i8* swiftasync %0)
|
|||||||
; CHECK: attributes #45 = { vscale_range(8,8) }
|
; CHECK: attributes #45 = { vscale_range(8,8) }
|
||||||
; CHECK: attributes #46 = { vscale_range(1,8) }
|
; CHECK: attributes #46 = { vscale_range(1,8) }
|
||||||
; CHECK: attributes #47 = { vscale_range(1,0) }
|
; CHECK: attributes #47 = { vscale_range(1,0) }
|
||||||
|
; CHECK: attributes #48 = { nosanitize_coverage }
|
||||||
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
|
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
|
||||||
|
@ -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>
|
; 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
|
call void @f.nobuiltin() builtin
|
||||||
; CHECK: call void @f.nobuiltin() #44
|
; CHECK: call void @f.nobuiltin() #45
|
||||||
|
|
||||||
call fastcc noalias i32* @f.noalias() noinline
|
call fastcc noalias i32* @f.noalias() noinline
|
||||||
; CHECK: call fastcc noalias i32* @f.noalias() #12
|
; CHECK: call fastcc noalias i32* @f.noalias() #12
|
||||||
@ -1904,6 +1904,9 @@ define void @instructions.strictfp() strictfp {
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @f.nosanitize_coverage() nosanitize_coverage
|
||||||
|
; CHECK: declare void @f.nosanitize_coverage() #44
|
||||||
|
|
||||||
; immarg attribute
|
; immarg attribute
|
||||||
declare void @llvm.test.immarg.intrinsic(i32 immarg)
|
declare void @llvm.test.immarg.intrinsic(i32 immarg)
|
||||||
; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)
|
; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)
|
||||||
@ -1961,7 +1964,8 @@ declare void @byval_named_type(%named_type* byval(%named_type))
|
|||||||
; CHECK: attributes #41 = { writeonly }
|
; CHECK: attributes #41 = { writeonly }
|
||||||
; CHECK: attributes #42 = { speculatable }
|
; CHECK: attributes #42 = { speculatable }
|
||||||
; CHECK: attributes #43 = { strictfp }
|
; CHECK: attributes #43 = { strictfp }
|
||||||
; CHECK: attributes #44 = { builtin }
|
; CHECK: attributes #44 = { nosanitize_coverage }
|
||||||
|
; CHECK: attributes #45 = { builtin }
|
||||||
|
|
||||||
;; Metadata
|
;; Metadata
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "inaccessiblememonly"
|
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "inaccessiblememonly"
|
||||||
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull"
|
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull"
|
||||||
"nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
|
"nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
|
||||||
"norecurse" "nosync" "noundef" "nounwind" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
|
"norecurse" "nosync" "noundef" "nounwind" "nosanitize_coverage" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
|
||||||
"shadowcallstack" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag"
|
"shadowcallstack" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag"
|
||||||
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
|
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
|
||||||
;; Variables
|
;; Variables
|
||||||
|
@ -176,6 +176,7 @@ FuncAttr ::= noreturn
|
|||||||
| sanitize_thread
|
| sanitize_thread
|
||||||
| sanitize_memory
|
| sanitize_memory
|
||||||
| mustprogress
|
| mustprogress
|
||||||
|
| nosanitize_coverage
|
||||||
;
|
;
|
||||||
|
|
||||||
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
|
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
|
||||||
|
@ -138,6 +138,7 @@ syn keyword llvmKeyword
|
|||||||
\ nosync
|
\ nosync
|
||||||
\ noundef
|
\ noundef
|
||||||
\ nounwind
|
\ nounwind
|
||||||
|
\ nosanitize_coverage
|
||||||
\ null_pointer_is_valid
|
\ null_pointer_is_valid
|
||||||
\ optforfuzzing
|
\ optforfuzzing
|
||||||
\ optnone
|
\ optnone
|
||||||
|
@ -237,6 +237,7 @@ patterns:
|
|||||||
\\bnosync\\b|\
|
\\bnosync\\b|\
|
||||||
\\bnoundef\\b|\
|
\\bnoundef\\b|\
|
||||||
\\bnounwind\\b|\
|
\\bnounwind\\b|\
|
||||||
|
\\bnosanitize_coverage\\b|\
|
||||||
\\bnull_pointer_is_valid\\b|\
|
\\bnull_pointer_is_valid\\b|\
|
||||||
\\boptforfuzzing\\b|\
|
\\boptforfuzzing\\b|\
|
||||||
\\boptnone\\b|\
|
\\boptnone\\b|\
|
||||||
|
Loading…
x
Reference in New Issue
Block a user