Skip to content

[UBSan] Implement src:*=sanitize for UBSan #140529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b83755d
[𝘀𝗽𝗿] initial version
qinkunbao May 19, 2025
51abb3b
Fix format
qinkunbao May 19, 2025
df61d7a
Fix format
qinkunbao May 19, 2025
117144c
remove braces for simple statements.
qinkunbao May 19, 2025
b2f90f5
[𝘀𝗽𝗿] changes introduced through rebase
qinkunbao May 19, 2025
e499598
rebase
qinkunbao May 19, 2025
c9d4f4f
[𝘀𝗽𝗿] changes introduced through rebase
qinkunbao May 19, 2025
caa59da
rebase
qinkunbao May 19, 2025
28b35ef
rebase
qinkunbao May 19, 2025
5c2363d
rebase
qinkunbao May 19, 2025
af1c6c8
Update SpecialCaseList.cpp
qinkunbao May 20, 2025
406bbd4
Update SanitizerSpecialCaseList.rst and ReleaseNotes.rst
qinkunbao May 20, 2025
80b2c18
fix doc
qinkunbao May 20, 2025
898658c
remove the second lookup in containsFile.
qinkunbao May 20, 2025
9be5d44
Add unit tests for inSectionBlame
qinkunbao May 20, 2025
9c37ea0
Update the docs
qinkunbao May 20, 2025
c6e4f8e
Merge branch 'main' into users/qinkunbao/spr/implement-srcsanitize-fo…
qinkunbao May 21, 2025
79610ab
Address test cases for contradict5 and contradict6.
qinkunbao May 21, 2025
bfd7cba
Update the doc.
qinkunbao May 21, 2025
9966e67
Update the doc.
qinkunbao May 21, 2025
815c4c2
Merge branch 'main' into users/qinkunbao/spr/implement-srcsanitize-fo…
qinkunbao May 24, 2025
fc352fb
Update with the new globs
qinkunbao May 24, 2025
8b5684d
Update the tests.
qinkunbao May 24, 2025
6be9bfd
Add more tests.
qinkunbao May 26, 2025
f582891
iterate SanitizerSections reverse.
qinkunbao May 27, 2025
2a8adf6
Merge branch 'main' into users/qinkunbao/spr/implement-srcsanitize-fo…
qinkunbao May 27, 2025
73f0de8
Merge branch 'main' into users/qinkunbao/spr/implement-srcsanitize-fo…
qinkunbao May 27, 2025
1167303
Merge branch 'main' into users/qinkunbao/spr/implement-srcsanitize-fo…
qinkunbao May 27, 2025
9b1d03c
rebase
qinkunbao May 28, 2025
8884762
fix build
qinkunbao May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ Sanitizers
----------

- ``-fsanitize=vptr`` is no longer a part of ``-fsanitize=undefined``.
- Sanitizer ignorelists now support the syntax ``src:*=sanitize``.

Python Binding Changes
----------------------
Expand Down
26 changes: 21 additions & 5 deletions clang/docs/SanitizerSpecialCaseList.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Usage with UndefinedBehaviorSanitizer
ability to adjust instrumentation based on type.

By default, supported sanitizers will have their instrumentation disabled for
types specified within an ignorelist.
entries specified within an ignorelist.

.. code-block:: bash

Expand All @@ -77,10 +77,9 @@ For example, supplying the above ``ignorelist.txt`` to
``-fsanitize-ignorelist=ignorelist.txt`` disables overflow sanitizer
instrumentation for arithmetic operations containing values of type ``int``.

The ``=sanitize`` category is also supported. Any types assigned to the
``sanitize`` category will have their sanitizer instrumentation remain. If the
same type appears within or across ignorelists with different categories the
``sanitize`` category takes precedence -- regardless of order.
The ``=sanitize`` category is also supported. Any ``=sanitize`` category
entries enable sanitizer instrumentation, even if it was ignored by entries
before.

With this, one may disable instrumentation for some or all types and
specifically allow instrumentation for one or many types -- including types
Expand All @@ -103,6 +102,23 @@ supported sanitizers.
char c = toobig; // also not instrumented
}

If multiple entries match the source, than the latest entry takes the
precedence.

.. code-block:: bash

$ cat ignorelist1.txt
# test.cc will be instrumented.
src:*
src:*/mylib/*=sanitize
src:*/mylib/test.cc

$ cat ignorelist2.txt
# test.cc will not be instrumented.
src:*
src:*/mylib/test.cc
src:*/mylib/*=sanitize

Format
======

Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Basic/SanitizerSpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,18 @@ class SanitizerSpecialCaseList : public llvm::SpecialCaseList {
bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
StringRef Category = StringRef()) const;

// Query ignorelisted entries if any bit in Mask matches the entry's section.
// Return 0 if not found. If found, return the line number (starts with 1).
unsigned inSectionBlame(SanitizerMask Mask, StringRef Prefix, StringRef Query,
StringRef Category = StringRef()) const;

protected:
// Initialize SanitizerSections.
void createSanitizerSections();

struct SanitizerSection {
SanitizerSection(SanitizerMask SM, SectionEntries &E)
: Mask(SM), Entries(E){};
: Mask(SM), Entries(E) {};

SanitizerMask Mask;
SectionEntries &Entries;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Basic/NoSanitizeList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ bool NoSanitizeList::containsFunction(SanitizerMask Mask,

bool NoSanitizeList::containsFile(SanitizerMask Mask, StringRef FileName,
StringRef Category) const {
return SSCL->inSection(Mask, "src", FileName, Category);
unsigned NoSanLine = SSCL->inSectionBlame(Mask, "src", FileName, Category);
if (NoSanLine == 0)
return false;
unsigned SanLine = SSCL->inSectionBlame(Mask, "src", FileName, "sanitize");
// If we have two cases such as `src:a.cpp=sanitize` and `src:a.cpp`, the
// current entry override the previous entry.
return !SanLine || NoSanLine > SanLine;
}

bool NoSanitizeList::containsMainFile(SanitizerMask Mask, StringRef FileName,
Expand Down
21 changes: 16 additions & 5 deletions clang/lib/Basic/SanitizerSpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/SanitizerSpecialCaseList.h"
#include "llvm/ADT/STLExtras.h"

using namespace clang;

Expand Down Expand Up @@ -56,10 +57,20 @@ void SanitizerSpecialCaseList::createSanitizerSections() {
bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix,
StringRef Query,
StringRef Category) const {
for (auto &S : SanitizerSections)
if ((S.Mask & Mask) &&
SpecialCaseList::inSectionBlame(S.Entries, Prefix, Query, Category))
return true;
return inSectionBlame(Mask, Prefix, Query, Category);
}

return false;
unsigned SanitizerSpecialCaseList::inSectionBlame(SanitizerMask Mask,
StringRef Prefix,
StringRef Query,
StringRef Category) const {
for (const auto &S : llvm::reverse(SanitizerSections)) {
if (S.Mask & Mask) {
unsigned lineNum =
SpecialCaseList::inSectionBlame(S.Entries, Prefix, Query, Category);
if (lineNum > 0)
return lineNum;
}
}
return 0;
}
36 changes: 31 additions & 5 deletions clang/test/CodeGen/ubsan-src-ignorelist-category.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test2.c -o - | FileCheck %s --check-prefixes=CHECK2

// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict1 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict2 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict2 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please in separate PR extend this test for:

  1. category - seems like your fix has no issues with that, but it would be nice to have test coverage
  2. multiple files (or maybe llvm-project/llvm/unittests/Support/SpecialCaseListTest.cpp will be enough)

// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict3 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict4 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict4 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict5 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict6 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE

// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict6 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict7 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict8 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE

// Verify ubsan only emits checks for files in the allowlist

Expand Down Expand Up @@ -52,6 +53,31 @@ src:*/tes*1.c=sanitize
src:*/te*t1.c
src:*/t*st1.c=sanitize

//--- src.ignorelist.contradict7
[{unsigned-integer-overflow,signed-integer-overflow}]
src:*
src:*/tes*1.c=sanitize
src:*/te*t1.c
src:*/t*st1.c=sanitize
[{unsigned-integer-overflow,signed-integer-overflow}]
src:*
src:*/te*t1.c
src:*/tes*1.c=sanitize
src:*/test1.c

//--- src.ignorelist.contradict8
[{unsigned-integer-overflow,signed-integer-overflow}]
src:*
src:*/te*t1.c
src:*/tes*1.c=sanitize
src:*/test1.c
[{unsigned-integer-overflow,signed-integer-overflow}]
src:*
src:*/tes*1.c=sanitize
src:*/te*t1.c
src:*/t*st1.c=sanitize


//--- test1.c
// CHECK1-LABEL: define dso_local i32 @add
int add(int a, int b) {
Expand Down
Loading