[clang] 0d5a62f - [sanitizer] Add "mainfile" prefix to sanitizer special case list

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 15 10:39:33 PDT 2022


Author: Fangrui Song
Date: 2022-07-15T10:39:26-07:00
New Revision: 0d5a62faca5924c5a197faa946b5b78b3d80a0b2

URL: https://github.com/llvm/llvm-project/commit/0d5a62faca5924c5a197faa946b5b78b3d80a0b2
DIFF: https://github.com/llvm/llvm-project/commit/0d5a62faca5924c5a197faa946b5b78b3d80a0b2.diff

LOG: [sanitizer] Add "mainfile" prefix to sanitizer special case list

When an issue exists in the main file (caller) instead of an included file
(callee), using a `src` pattern applying to the included file may be
inappropriate if it's the caller's responsibility. Add `mainfile` prefix to check
the main filename.

For the example below, the issue may reside in a.c (foo should not be called
with a misaligned pointer or foo should switch to an unaligned load), but with
`src` we can only apply to the innocent callee a.h. With this patch we can use
the more appropriate `mainfile:a.c`.
```
//--- a.h
// internal linkage
static inline int load(int *x) { return *x; }

//--- a.c, -fsanitize=alignment
#include "a.h"
int foo(void *x) { return load(x); }
```

See the updated clang/docs/SanitizerSpecialCaseList.rst for a caveat due
to C++ vague linkage functions.

Reviewed By: #sanitizers, kstoimenov, vitalybuka

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

Added: 
    clang/test/CodeGen/sanitize-ignorelist-mainfile.c

Modified: 
    clang/docs/SanitizerSpecialCaseList.rst
    clang/include/clang/Basic/NoSanitizeList.h
    clang/lib/Basic/NoSanitizeList.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    llvm/include/llvm/Support/SpecialCaseList.h

Removed: 
    


################################################################################
diff  --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst
index cbb00fde9bb7..15e19b9c129c 100644
--- a/clang/docs/SanitizerSpecialCaseList.rst
+++ b/clang/docs/SanitizerSpecialCaseList.rst
@@ -75,6 +75,9 @@ tool-specific docs.
     # Turn off checks for the source file (use absolute path or path relative
     # to the current working directory):
     src:/path/to/source/file.c
+    # Turn off checks for this main file, including files included by it.
+    # Useful when the main file instead of an included file should be ignored.
+    mainfile:file.c
     # Turn off checks for a particular functions (use mangled names):
     fun:MyFooBar
     fun:_Z8MyFooBarv
@@ -93,3 +96,18 @@ tool-specific docs.
     [cfi-vcall|cfi-icall]
     fun:*BadCfiCall
     # Entries without sections are placed into [*] and apply to all sanitizers
+
+``mainfile`` is similar to applying ``-fno-sanitize=`` to a set of files but
+does not need plumbing into the build system. This works well for internal
+linkage functions but has a caveat for C++ vague linkage functions.
+
+C++ vague linkage functions (e.g. inline functions, template instantiations) are
+deduplicated at link time. A function (in an included file) ignored by a
+specific ``mainfile`` pattern may not be the prevailing copy picked by the
+linker. Therefore, using ``mainfile`` requires caution. It may still be useful,
+e.g. when patterns are picked in a way to ensure the prevailing one is ignored.
+(There is action-at-a-distance risk.)
+
+``mainfile`` can be useful enabling a ubsan check for a large code base when
+finding the direct stack frame triggering the failure for every failure is
+
diff icult.

diff  --git a/clang/include/clang/Basic/NoSanitizeList.h b/clang/include/clang/Basic/NoSanitizeList.h
index 3f80e0fdedda..43415859fcd5 100644
--- a/clang/include/clang/Basic/NoSanitizeList.h
+++ b/clang/include/clang/Basic/NoSanitizeList.h
@@ -41,6 +41,8 @@ class NoSanitizeList {
   bool containsFunction(SanitizerMask Mask, StringRef FunctionName) const;
   bool containsFile(SanitizerMask Mask, StringRef FileName,
                     StringRef Category = StringRef()) const;
+  bool containsMainFile(SanitizerMask Mask, StringRef FileName,
+                        StringRef Category = StringRef()) const;
   bool containsLocation(SanitizerMask Mask, SourceLocation Loc,
                         StringRef Category = StringRef()) const;
 };

diff  --git a/clang/lib/Basic/NoSanitizeList.cpp b/clang/lib/Basic/NoSanitizeList.cpp
index 3efd613b0d33..e7e63c1f419e 100644
--- a/clang/lib/Basic/NoSanitizeList.cpp
+++ b/clang/lib/Basic/NoSanitizeList.cpp
@@ -47,6 +47,11 @@ bool NoSanitizeList::containsFile(SanitizerMask Mask, StringRef FileName,
   return SSCL->inSection(Mask, "src", FileName, Category);
 }
 
+bool NoSanitizeList::containsMainFile(SanitizerMask Mask, StringRef FileName,
+                                      StringRef Category) const {
+  return SSCL->inSection(Mask, "mainfile", FileName, Category);
+}
+
 bool NoSanitizeList::containsLocation(SanitizerMask Mask, SourceLocation Loc,
                                       StringRef Category) const {
   return Loc.isValid() &&

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 1e90b0914538..4daf4120e0ca 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2780,16 +2780,18 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn,
   // NoSanitize by function name.
   if (NoSanitizeL.containsFunction(Kind, Fn->getName()))
     return true;
-  // NoSanitize by location.
+  // NoSanitize by location. Check "mainfile" prefix.
+  auto &SM = Context.getSourceManager();
+  const FileEntry &MainFile = *SM.getFileEntryForID(SM.getMainFileID());
+  if (NoSanitizeL.containsMainFile(Kind, MainFile.getName()))
+    return true;
+
+  // Check "src" prefix.
   if (Loc.isValid())
     return NoSanitizeL.containsLocation(Kind, Loc);
   // If location is unknown, this may be a compiler-generated function. Assume
   // it's located in the main file.
-  auto &SM = Context.getSourceManager();
-  if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
-    return NoSanitizeL.containsFile(Kind, MainFile->getName());
-  }
-  return false;
+  return NoSanitizeL.containsFile(Kind, MainFile.getName());
 }
 
 bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind,
@@ -2799,8 +2801,13 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind,
   const auto &NoSanitizeL = getContext().getNoSanitizeList();
   if (NoSanitizeL.containsGlobal(Kind, GV->getName(), Category))
     return true;
+  auto &SM = Context.getSourceManager();
+  if (NoSanitizeL.containsMainFile(
+          Kind, SM.getFileEntryForID(SM.getMainFileID())->getName(), Category))
+    return true;
   if (NoSanitizeL.containsLocation(Kind, Loc, Category))
     return true;
+
   // Check global type.
   if (!Ty.isNull()) {
     // Drill down the array types: if global variable of a fixed type is

diff  --git a/clang/test/CodeGen/sanitize-ignorelist-mainfile.c b/clang/test/CodeGen/sanitize-ignorelist-mainfile.c
new file mode 100644
index 000000000000..84d58b4c018e
--- /dev/null
+++ b/clang/test/CodeGen/sanitize-ignorelist-mainfile.c
@@ -0,0 +1,41 @@
+/// Test mainfile in a sanitizer special case list.
+// RUN: rm -rf %t && split-file %s %t && cd %t
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize=address,alignment a.c -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize=address,alignment -fsanitize-ignorelist=a.list a.c -o - | FileCheck %s --check-prefixes=CHECK,IGNORE
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fsanitize=address,alignment -fsanitize-ignorelist=b.list a.c -o - | FileCheck %s --check-prefixes=CHECK,IGNORE
+
+//--- a.list
+mainfile:*a.c
+
+//--- b.list
+[address]
+mainfile:*a.c
+
+[alignment]
+mainfile:*.c
+
+//--- a.h
+int global_h;
+
+static inline int load(int *x) {
+  return *x;
+}
+
+//--- a.c
+#include "a.h"
+
+int global_c;
+
+int foo(void *x) {
+  return load(x);
+}
+
+// DEFAULT:     @___asan_gen_{{.*}} = {{.*}} c"global_h\00"
+// DEFAULT:     @___asan_gen_{{.*}} = {{.*}} c"global_c\00"
+// IGNORE-NOT:  @___asan_gen_
+
+// CHECK-LABEL: define {{.*}}@load(
+// DEFAULT:       call void @__ubsan_handle_type_mismatch_v1_abort(
+// DEFAULT:       call void @__asan_report_load4(
+// IGNORE-NOT:    call void @__ubsan_handle_type_mismatch_v1_abort(
+// IGNORE-NOT:    call void @__asan_report_load4(

diff  --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h
index d022a8f53706..0d56c4b9912d 100644
--- a/llvm/include/llvm/Support/SpecialCaseList.h
+++ b/llvm/include/llvm/Support/SpecialCaseList.h
@@ -19,9 +19,9 @@
 //   prefix:wildcard_expression[=category]
 // If category is not specified, it is assumed to be empty string.
 // Definitions of "prefix" and "category" are sanitizer-specific. For example,
-// sanitizer exclusion support prefixes "src", "fun" and "global".
-// Wildcard expressions define, respectively, source files, functions or
-// globals which shouldn't be instrumented.
+// sanitizer exclusion support prefixes "src", "mainfile", "fun" and "global".
+// Wildcard expressions define, respectively, source files, main files,
+// functions or globals which shouldn't be instrumented.
 // Examples of categories:
 //   "functional": used in DFSan to list functions with pure functional
 //                 semantics.
@@ -37,6 +37,7 @@
 // type:*Namespace::ClassName*=init
 // src:file_with_tricky_code.cc
 // src:ignore-global-initializers-issues.cc=init
+// mainfile:main_file.cc
 //
 // [dataflow]
 // # Functions with pure functional semantics:


        


More information about the cfe-commits mailing list