} while (false);
if (D) {
+ const bool SanitizeBounds = SanOpts.hasOneOf(SanitizerKind::Bounds);
bool NoSanitizeCoverage = false;
for (auto Attr : D->specific_attrs<NoSanitizeAttr>()) {
NoSanitizeCoverage = true;
}
+ if (SanitizeBounds && !SanOpts.hasOneOf(SanitizerKind::Bounds))
+ Fn->addFnAttr(llvm::Attribute::NoSanitizeBounds);
+
if (NoSanitizeCoverage && CGM.getCodeGenOpts().hasSanitizeCoverage())
Fn->addFnAttr(llvm::Attribute::NoSanitizeCoverage);
}
return u->c[i];
// CHECK: }
}
+
+__attribute__((no_sanitize("bounds")))
+int f6(int i) {
+ int b[64];
+ // CHECK-NOT: call void @llvm.trap()
+ // CHECK-NOT: trap:
+ // CHECK-NOT: cont:
+ return b[i];
+}
// ASAN-NOT: call void @__asan_report_store
// MSAN-NOT: call void @__msan_warning
// BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds
+ // BOUNDS-NOT: call void @llvm.trap()
// TSAN-NOT: call void @__tsan_func_entry
// UBSAN-NOT: call void @__ubsan_handle
if (n)
// ASAN-NOT: call void @__asan_report_store
// MSAN-NOT: call void @__msan_warning
// BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds
+ // BOUNDS-NOT: call void @llvm.trap()
// TSAN-NOT: call void @__tsan_func_entry
// UBSAN-NOT: call void @__ubsan_handle
if (n)
"noredzone",
"noreturn",
"nounwind",
+ "nosanitize_bounds",
"nosanitize_coverage",
"optnone",
"optsize",
* code 76: ``nosanitize_coverage``
* code 77: ``elementtype``
* code 78: ``disable_sanitizer_instrumentation``
+* code 79: ``nosanitize_bounds``
.. note::
The ``allocsize`` attribute has a special encoding for its arguments. Its two
trap or generate asynchronous exceptions. Exception handling schemes
that are recognized by LLVM to handle asynchronous exceptions, such
as SEH, will still provide their implementation defined semantics.
+``nosanitize_bounds``
+ This attribute indicates that bounds checking sanitizer instrumentation
+ is disabled for this function.
``nosanitize_coverage``
This attribute indicates that SanitizerCoverage instrumentation is disabled
for this function.
kw_nosync,
kw_nocf_check,
kw_nounwind,
+ kw_nosanitize_bounds,
kw_nosanitize_coverage,
kw_null_pointer_is_valid,
kw_optforfuzzing,
ATTR_KIND_NO_SANITIZE_COVERAGE = 76,
ATTR_KIND_ELEMENTTYPE = 77,
ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION = 78,
+ ATTR_KIND_NO_SANITIZE_BOUNDS = 79,
};
enum ComdatSelectionKindCodes {
/// Function doesn't unwind stack.
def NoUnwind : EnumAttr<"nounwind", [FnAttr]>;
+/// No SanitizeBounds instrumentation.
+def NoSanitizeBounds : EnumAttr<"nosanitize_bounds", [FnAttr]>;
+
/// No SanitizeCoverage instrumentation.
def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage", [FnAttr]>;
KEYWORD(nocf_check);
KEYWORD(noundef);
KEYWORD(nounwind);
+ KEYWORD(nosanitize_bounds);
KEYWORD(nosanitize_coverage);
KEYWORD(null_pointer_is_valid);
KEYWORD(optforfuzzing);
return Attribute::NoProfile;
case bitc::ATTR_KIND_NO_UNWIND:
return Attribute::NoUnwind;
+ case bitc::ATTR_KIND_NO_SANITIZE_BOUNDS:
+ return Attribute::NoSanitizeBounds;
case bitc::ATTR_KIND_NO_SANITIZE_COVERAGE:
return Attribute::NoSanitizeCoverage;
case bitc::ATTR_KIND_NULL_POINTER_IS_VALID:
return bitc::ATTR_KIND_NO_PROFILE;
case Attribute::NoUnwind:
return bitc::ATTR_KIND_NO_UNWIND;
+ case Attribute::NoSanitizeBounds:
+ return bitc::ATTR_KIND_NO_SANITIZE_BOUNDS;
case Attribute::NoSanitizeCoverage:
return bitc::ATTR_KIND_NO_SANITIZE_COVERAGE;
case Attribute::NullPointerIsValid:
static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
ScalarEvolution &SE) {
+ if (F.hasFnAttribute(Attribute::NoSanitizeBounds))
+ return false;
+
const DataLayout &DL = F.getParent()->getDataLayout();
ObjectSizeOpts EvalOpts;
EvalOpts.RoundToAlign = true;
case Attribute::NonLazyBind:
case Attribute::NoRedZone:
case Attribute::NoUnwind:
+ case Attribute::NoSanitizeBounds:
case Attribute::NoSanitizeCoverage:
case Attribute::NullPointerIsValid:
case Attribute::OptForFuzzing:
ret void;
}
+; CHECK: define void @f86() #52
+define void @f86() nosanitize_bounds
+{
+ ret void;
+}
+
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
; CHECK: attributes #49 = { noprofile }
; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
; CHECK: attributes #51 = { uwtable(sync) }
+; CHECK: attributes #52 = { nosanitize_bounds }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
; 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() #48
+ ; CHECK: call void @f.nobuiltin() #49
call fastcc noalias i32* @f.noalias() noinline
; CHECK: call fastcc noalias i32* @f.noalias() #12
; CHECK: Function Attrs: allocsize(1,0)
; CHECK: declare void @f.allocsize_two(i32, i32)
+declare void @f.nosanitize_bounds() nosanitize_bounds
+; CHECK: declare void @f.nosanitize_bounds() #48
+
; CHECK: attributes #0 = { alignstack=4 }
; CHECK: attributes #1 = { alignstack=8 }
; CHECK: attributes #2 = { alwaysinline }
; CHECK: attributes #45 = { disable_sanitizer_instrumentation }
; CHECK: attributes #46 = { allocsize(0) }
; CHECK: attributes #47 = { allocsize(1,0) }
-; CHECK: attributes #48 = { builtin }
+; CHECK: attributes #48 = { nosanitize_bounds }
+; CHECK: attributes #49 = { builtin }
;; Metadata
--- /dev/null
+; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s
+target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; CHECK: @foo
+define i32 @foo(i32 %i) nosanitize_bounds {
+entry:
+ %i.addr = alloca i32, align 4
+ %b = alloca [64 x i32], align 16
+ store i32 %i, i32* %i.addr, align 4
+ %0 = load i32, i32* %i.addr, align 4
+ %idxprom = sext i32 %0 to i64
+ %arrayidx = getelementptr inbounds [64 x i32], [64 x i32]* %b, i64 0, i64 %idxprom
+ %1 = load i32, i32* %arrayidx, align 4
+ ret i32 %1
+; CHECK-NOT: call void @llvm.trap()
+}
+
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "inaccessiblememonly"
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull"
"nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
- "norecurse" "nosync" "noundef" "nounwind" "nosanitize_coverage" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
+ "norecurse" "nosync" "noundef" "nounwind" "nosanitize_bounds" "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"
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
;; Variables
| sanitize_thread
| sanitize_memory
| mustprogress
+ | nosanitize_bounds
| nosanitize_coverage
;
\ nosync
\ noundef
\ nounwind
+ \ nosanitize_bounds
\ nosanitize_coverage
\ null_pointer_is_valid
\ optforfuzzing
\\bnosync\\b|\
\\bnoundef\\b|\
\\bnounwind\\b|\
+ \\bnosanitize_bounds\\b|\
\\bnosanitize_coverage\\b|\
\\bnull_pointer_is_valid\\b|\
\\boptforfuzzing\\b|\