[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