[llvm] 17ce89f - [SanitizerBounds] Add support for NoSanitizeBounds function

Marco Elver via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 1 09:48:27 PST 2022


Author: Tong Zhang
Date: 2022-03-01T18:47:02+01:00
New Revision: 17ce89fa8016758be2ec879c5560e506cad4c362

URL: https://github.com/llvm/llvm-project/commit/17ce89fa8016758be2ec879c5560e506cad4c362
DIFF: https://github.com/llvm/llvm-project/commit/17ce89fa8016758be2ec879c5560e506cad4c362.diff

LOG: [SanitizerBounds] Add support for NoSanitizeBounds function

Currently adding attribute no_sanitize("bounds") isn't disabling
-fsanitize=local-bounds (also enabled in -fsanitize=bounds). The Clang
frontend handles fsanitize=array-bounds which can already be disabled by
no_sanitize("bounds"). However, instrumentation added by the
BoundsChecking pass in the middle-end cannot be disabled by the
attribute.

The fix is very similar to D102772 that added the ability to selectively
disable sanitizer pass on certain functions.

In this patch, if no_sanitize("bounds") is provided, an additional
function attribute (NoSanitizeBounds) is attached to IR to let the
BoundsChecking pass know we want to disable local-bounds checking. In
order to support this feature, the IR is extended (similar to D102772)
to make Clang able to preserve the information and let BoundsChecking
pass know bounds checking is disabled for certain function.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D119816

Added: 
    llvm/test/Instrumentation/BoundsChecking/nosanitize-bounds.ll

Modified: 
    clang/lib/CodeGen/CodeGenFunction.cpp
    clang/test/CodeGen/bounds-checking.c
    clang/test/CodeGen/sanitize-coverage.c
    llvm/bindings/go/llvm/ir_test.go
    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/Instrumentation/BoundsChecking.cpp
    llvm/lib/Transforms/Utils/CodeExtractor.cpp
    llvm/test/Bitcode/attributes.ll
    llvm/test/Bitcode/compatibility.ll
    llvm/utils/emacs/llvm-mode.el
    llvm/utils/llvm.grm
    llvm/utils/vim/syntax/llvm.vim
    llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 9c3e5d5460014..c1f3a3014a192 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -740,6 +740,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
   } while (false);
 
   if (D) {
+    const bool SanitizeBounds = SanOpts.hasOneOf(SanitizerKind::Bounds);
     bool NoSanitizeCoverage = false;
 
     for (auto Attr : D->specific_attrs<NoSanitizeAttr>()) {
@@ -760,6 +761,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
         NoSanitizeCoverage = true;
     }
 
+    if (SanitizeBounds && !SanOpts.hasOneOf(SanitizerKind::Bounds))
+      Fn->addFnAttr(llvm::Attribute::NoSanitizeBounds);
+
     if (NoSanitizeCoverage && CGM.getCodeGenOpts().hasSanitizeCoverage())
       Fn->addFnAttr(llvm::Attribute::NoSanitizeCoverage);
   }

diff  --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c
index ba8c18934388c..25b767c7fa0d9 100644
--- a/clang/test/CodeGen/bounds-checking.c
+++ b/clang/test/CodeGen/bounds-checking.c
@@ -49,3 +49,12 @@ int f5(union U *u, int i) {
   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];
+}

diff  --git a/clang/test/CodeGen/sanitize-coverage.c b/clang/test/CodeGen/sanitize-coverage.c
index 6fd0adcb4a880..984076fed0ce4 100644
--- a/clang/test/CodeGen/sanitize-coverage.c
+++ b/clang/test/CodeGen/sanitize-coverage.c
@@ -53,6 +53,7 @@ void test_no_sanitize_combined(int 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)
@@ -72,6 +73,7 @@ void test_no_sanitize_separate(int 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)

diff  --git a/llvm/bindings/go/llvm/ir_test.go b/llvm/bindings/go/llvm/ir_test.go
index 61b482f2ef9a2..1aeb6e69bafb2 100644
--- a/llvm/bindings/go/llvm/ir_test.go
+++ b/llvm/bindings/go/llvm/ir_test.go
@@ -69,6 +69,7 @@ func TestAttributes(t *testing.T) {
 		"noredzone",
 		"noreturn",
 		"nounwind",
+		"nosanitize_bounds",
 		"nosanitize_coverage",
 		"optnone",
 		"optsize",

diff  --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst
index 8e81a7daa4593..56268f1523cc4 100644
--- a/llvm/docs/BitCodeFormat.rst
+++ b/llvm/docs/BitCodeFormat.rst
@@ -1078,6 +1078,7 @@ The integer codes are mapped to well-known attributes as follows.
 * 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

diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index df7065cecd253..3d54e25d47619 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1783,6 +1783,9 @@ example:
     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.

diff  --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index faac67ebbab96..7b0cf69bce2d4 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -219,6 +219,7 @@ enum Kind {
   kw_nosync,
   kw_nocf_check,
   kw_nounwind,
+  kw_nosanitize_bounds,
   kw_nosanitize_coverage,
   kw_null_pointer_is_valid,
   kw_optforfuzzing,

diff  --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 6d0f51ce9c6d0..a026b44bf32f2 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -677,6 +677,7 @@ enum AttributeKindCodes {
   ATTR_KIND_NO_SANITIZE_COVERAGE = 76,
   ATTR_KIND_ELEMENTTYPE = 77,
   ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION = 78,
+  ATTR_KIND_NO_SANITIZE_BOUNDS = 79,
 };
 
 enum ComdatSelectionKindCodes {

diff  --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index d7a79f90e05e8..a0ab91382691e 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -175,6 +175,9 @@ def NoProfile : EnumAttr<"noprofile", [FnAttr]>;
 /// 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]>;
 

diff  --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index a508660edfa59..3f0c60fd571af 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -672,6 +672,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(nocf_check);
   KEYWORD(noundef);
   KEYWORD(nounwind);
+  KEYWORD(nosanitize_bounds);
   KEYWORD(nosanitize_coverage);
   KEYWORD(null_pointer_is_valid);
   KEYWORD(optforfuzzing);

diff  --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index dee8c4daaadae..5cd29e7f7923f 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1493,6 +1493,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     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:

diff  --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 4bba0b3566751..6b5147ff7807d 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -688,6 +688,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     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:

diff  --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
index 4ad07cab001ad..d7b7b73ed9d5e 100644
--- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
+++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
@@ -142,6 +142,9 @@ static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) {
 
 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;

diff  --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index cec159f6a448f..01d149c7d6191 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -939,6 +939,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
       case Attribute::NonLazyBind:
       case Attribute::NoRedZone:
       case Attribute::NoUnwind:
+      case Attribute::NoSanitizeBounds:
       case Attribute::NoSanitizeCoverage:
       case Attribute::NullPointerIsValid:
       case Attribute::OptForFuzzing:

diff  --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index 5d3828d2762d2..ee582cab628dc 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -526,6 +526,12 @@ define void @f85() uwtable(async) {
         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 }
@@ -578,4 +584,5 @@ define void @f85() uwtable(async) {
 ; CHECK: attributes #49 = { noprofile }
 ; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
 ; CHECK: attributes #51 = { uwtable(sync) }
+; CHECK: attributes #52 = { nosanitize_bounds }
 ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }

diff  --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 1f0da632343eb..df8e0ac9ac3c7 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() #48
+  ; CHECK: call void @f.nobuiltin() #49
 
   call fastcc noalias i32* @f.noalias() noinline
   ; CHECK: call fastcc noalias i32* @f.noalias() #12
@@ -1930,6 +1930,9 @@ declare void @f.allocsize_two(i32, i32) allocsize(1, 0)
 ; 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 }
@@ -1978,7 +1981,8 @@ declare void @f.allocsize_two(i32, i32) allocsize(1, 0)
 ; 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
 

diff  --git a/llvm/test/Instrumentation/BoundsChecking/nosanitize-bounds.ll b/llvm/test/Instrumentation/BoundsChecking/nosanitize-bounds.ll
new file mode 100644
index 0000000000000..03efb3b1cd67d
--- /dev/null
+++ b/llvm/test/Instrumentation/BoundsChecking/nosanitize-bounds.ll
@@ -0,0 +1,17 @@
+; 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()
+}
+

diff  --git a/llvm/utils/emacs/llvm-mode.el b/llvm/utils/emacs/llvm-mode.el
index 1fb811b1d3c9a..c6d594d118d0b 100644
--- a/llvm/utils/emacs/llvm-mode.el
+++ b/llvm/utils/emacs/llvm-mode.el
@@ -25,7 +25,7 @@
        '("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

diff  --git a/llvm/utils/llvm.grm b/llvm/utils/llvm.grm
index be6dec78f9f50..411323178bde1 100644
--- a/llvm/utils/llvm.grm
+++ b/llvm/utils/llvm.grm
@@ -176,6 +176,7 @@ FuncAttr      ::= noreturn
  | sanitize_thread
  | sanitize_memory
  | mustprogress
+ | nosanitize_bounds
  | nosanitize_coverage
  ;
 

diff  --git a/llvm/utils/vim/syntax/llvm.vim b/llvm/utils/vim/syntax/llvm.vim
index 205db16b7d8cd..9185a029a22e5 100644
--- a/llvm/utils/vim/syntax/llvm.vim
+++ b/llvm/utils/vim/syntax/llvm.vim
@@ -139,6 +139,7 @@ syn keyword llvmKeyword
       \ nosync
       \ noundef
       \ nounwind
+      \ nosanitize_bounds
       \ nosanitize_coverage
       \ null_pointer_is_valid
       \ optforfuzzing

diff  --git a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
index 127f5d9867a09..d80c3778bbe78 100644
--- a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
+++ b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
@@ -238,6 +238,7 @@ patterns:
             \\bnosync\\b|\
             \\bnoundef\\b|\
             \\bnounwind\\b|\
+            \\bnosanitize_bounds\\b|\
             \\bnosanitize_coverage\\b|\
             \\bnull_pointer_is_valid\\b|\
             \\boptforfuzzing\\b|\


        


More information about the llvm-commits mailing list