Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
herobuxx committed Nov 4, 2024
2 parents 6ace1b0 + cec147a commit 6e4861e
Show file tree
Hide file tree
Showing 19 changed files with 500 additions and 119 deletions.
8 changes: 8 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,14 @@ Sanitizers
This new flag should allow those projects to enable integer sanitizers with
less noise.

- Arithmetic overflow sanitizers ``-fsanitize=signed-integer-overflow`` and
``-fsanitize=unsigned-integer-overflow`` as well as the implicit integer
truncation sanitizers ``-fsanitize=implicit-signed-integer-truncation`` and
``-fsanitize=implicit-unsigned-integer-truncation`` now properly support the
"type" prefix within `Sanitizer Special Case Lists (SSCL)
<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. See that link
for examples.

Python Binding Changes
----------------------
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
Expand Down
61 changes: 58 additions & 3 deletions clang/docs/SanitizerSpecialCaseList.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ file at compile-time.
Goal and usage
==============

Users of sanitizer tools, such as :doc:`AddressSanitizer`, :doc:`ThreadSanitizer`
or :doc:`MemorySanitizer` may want to disable or alter some checks for
certain source-level entities to:
Users of sanitizer tools, such as :doc:`AddressSanitizer`,
:doc:`ThreadSanitizer`, :doc:`MemorySanitizer` or :doc:`UndefinedBehaviorSanitizer`
may want to disable or alter some checks for certain source-level entities to:

* speedup hot function, which is known to be correct;
* ignore a function that does some low-level magic (e.g. walks through the
Expand Down Expand Up @@ -48,6 +48,61 @@ Example
$ clang -fsanitize=address -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# No error report here.
Usage with UndefinedBehaviorSanitizer
=====================================

The arithmetic overflow sanitizers ``unsigned-integer-overflow`` and
``signed-integer-overflow`` as well as the implicit integer truncation
sanitizers ``implicit-signed-integer-truncation`` and
``implicit-unsigned-integer-truncation`` support the ability to adjust
instrumentation based on type.

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

.. code-block:: bash
$ cat foo.c
void foo() {
int a = 2147483647; // INT_MAX
++a; // Normally, an overflow with -fsanitize=signed-integer-overflow
}
$ cat ignorelist.txt
[signed-integer-overflow]
type:int
$ clang -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# no signed-integer-overflow error
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.

With this, one may disable instrumentation for some or all types and
specifically allow instrumentation for one or many types -- including types
created via ``typedef``. This is a way to achieve a sort of "allowlist" for
supported sanitizers.

.. code-block:: bash
$ cat ignorelist.txt
[implicit-signed-integer-truncation]
type:*
type:T=sanitize
$ cat foo.c
typedef char T;
typedef char U;
void foo(int toobig) {
T a = toobig; // instrumented
U b = toobig; // not instrumented
char c = toobig; // also not instrumented
}
Format
======

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,9 @@ class ASTContext : public RefCountedBase<ASTContext> {

const NoSanitizeList &getNoSanitizeList() const { return *NoSanitizeL; }

bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
const QualType &Ty) const;

const XRayFunctionFilter &getXRayFilter() const {
return *XRayFilter;
}
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,15 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
return CanonTTP;
}

/// Check if a type can have its sanitizer instrumentation elided based on its
/// presence within an ignorelist.
bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
const QualType &Ty) const {
std::string TyName = Ty.getUnqualifiedType().getAsString(getPrintingPolicy());
return NoSanitizeL->containsType(Mask, TyName) &&
!NoSanitizeL->containsType(Mask, TyName, "sanitize");
}

TargetCXXABI::Kind ASTContext::getCXXABIKind() const {
auto Kind = getTargetInfo().getCXXABI().getKind();
return getLangOpts().CXXABI.value_or(Kind);
Expand Down
36 changes: 32 additions & 4 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,18 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
if (!Op.mayHaveIntegerOverflow())
return true;

if (Op.Ty->isSignedIntegerType() &&
Ctx.isTypeIgnoredBySanitizer(SanitizerKind::SignedIntegerOverflow,
Op.Ty)) {
return true;
}

if (Op.Ty->isUnsignedIntegerType() &&
Ctx.isTypeIgnoredBySanitizer(SanitizerKind::UnsignedIntegerOverflow,
Op.Ty)) {
return true;
}

const UnaryOperator *UO = dyn_cast<UnaryOperator>(Op.E);

if (UO && UO->getOpcode() == UO_Minus &&
Expand Down Expand Up @@ -1125,6 +1137,10 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
if (!CGF.SanOpts.has(Check.second.second))
return;

// Does some SSCL ignore this type?
if (CGF.getContext().isTypeIgnoredBySanitizer(Check.second.second, DstType))
return;

llvm::Constant *StaticArgs[] = {
CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType),
CGF.EmitCheckTypeDescriptor(DstType),
Expand Down Expand Up @@ -1235,6 +1251,15 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
// Because here sign change check is interchangeable with truncation check.
return;
}
// Does an SSCL have an entry for the DstType under its respective sanitizer
// section?
if (DstSigned && CGF.getContext().isTypeIgnoredBySanitizer(
SanitizerKind::ImplicitSignedIntegerTruncation, DstType))
return;
if (!DstSigned &&
CGF.getContext().isTypeIgnoredBySanitizer(
SanitizerKind::ImplicitUnsignedIntegerTruncation, DstType))
return;
// That's it. We can't rule out any more cases with the data we have.

CodeGenFunction::SanitizerScope SanScope(&CGF);
Expand Down Expand Up @@ -2784,10 +2809,11 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
return Builder.CreateNSWAdd(InVal, Amount, Name);
[[fallthrough]];
case LangOptions::SOB_Trapping:
if (!E->canOverflow())
BinOpInfo Info = createBinOpInfoFromIncDec(
E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts()));
if (!E->canOverflow() || CanElideOverflowCheck(CGF.getContext(), Info))
return Builder.CreateNSWAdd(InVal, Amount, Name);
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts())));
return EmitOverflowCheckedBinOp(Info);
}
llvm_unreachable("Unknown SignedOverflowBehaviorTy");
}
Expand Down Expand Up @@ -2990,7 +3016,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
} else if (E->canOverflow() && type->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
!excludeOverflowPattern) {
!excludeOverflowPattern &&
!CGF.getContext().isTypeIgnoredBySanitizer(
SanitizerKind::UnsignedIntegerOverflow, E->getType())) {
value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
E, value, isInc, E->getFPFeaturesInEffect(CGF.getLangOpts())));
} else {
Expand Down
58 changes: 58 additions & 0 deletions clang/test/CodeGen/ubsan-type-ignorelist-category-2.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// RUN: rm -rf %t
// RUN: split-file %s %t

// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-0.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-1.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-2.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-3.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-4.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-5.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-6.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-7.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s

// The same type can appear multiple times within an ignorelist. This is a test
// to make sure "=sanitize" has priority regardless of the order in which
// duplicate type entries appear. This is a precautionary measure; we would
// much rather eagerly sanitize than silently forgo sanitization.

//--- order-0.ignorelist
type:int
type:int=sanitize

//--- order-1.ignorelist
type:int=sanitize
type:int

//--- order-2.ignorelist
type:in*
type:int=sanitize

//--- order-3.ignorelist
type:in*=sanitize
type:int

//--- order-4.ignorelist
type:int
type:in*=sanitize

//--- order-5.ignorelist
type:int=sanitize
type:in*

//--- order-6.ignorelist
type:int=sanitize
type:in*

//--- order-7.ignorelist
type:int
type:int=sanitize




//--- test.c
// CHECK-LABEL: @test
void test(int A) {
// CHECK: @llvm.sadd.with.overflow.i32
++A;
}
98 changes: 98 additions & 0 deletions clang/test/CodeGen/ubsan-type-ignorelist-category.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// RUN: rm -rf %t
// RUN: split-file %s %t

// Verify ubsan doesn't emit checks for ignorelisted types
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/int.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/nosection.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/nosan-same-as-no-category.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/myty.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=MYTY
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t/trunc.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=TRUNC
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t/docs.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=TRUNC2

//--- int.ignorelist
[{unsigned-integer-overflow,signed-integer-overflow}]
type:int

//--- nosection.ignorelist
type:int

//--- nosan-same-as-no-category.ignorelist
type:int

//--- myty.ignorelist
[{unsigned-integer-overflow,signed-integer-overflow}]
type:*
type:myty=sanitize

//--- trunc.ignorelist
[{implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}]
type:char
type:unsigned char

//--- docs.ignorelist
[implicit-signed-integer-truncation]
type:*
type:T=sanitize

//--- test.cpp
// INT-LABEL: ignore_int
void ignore_int(int A, int B, unsigned C, unsigned D, long E) {
// INT: llvm.uadd.with.overflow.i32
(void)(C+D);
// INT-NOT: llvm.sadd.with.overflow.i32
(void)(A+B);
// INT: llvm.sadd.with.overflow.i64
(void)(++E);
}


typedef unsigned long myty;
typedef myty derivative;
// INT-LABEL: ignore_all_except_myty
// MYTY-LABEL: ignore_all_except_myty
void ignore_all_except_myty(myty A, myty B, int C, unsigned D, derivative E) {
// MYTY-NOT: llvm.sadd.with.overflow.i32
(void)(++C);

// MYTY-NOT: llvm.uadd.with.overflow.i32
(void)(D+D);

// MYTY-NOT: llvm.umul.with.overflow.i64
(void)(E*2);

// MYTY: llvm.uadd.with.overflow.i64
(void)(A+B);
}

// INT-LABEL: truncation
// MYTY-LABEL: truncation
// TRUNC-LABEL: truncation
void truncation(char A, int B, unsigned char C, short D) {
// TRUNC-NOT: %handler.implicit_conversion
A = B;
// TRUNC-NOT: %handler.implicit_conversion
A = C;
// TRUNC-NOT: %handler.implicit_conversion
C = B;

// TRUNC: %handler.implicit_conversion
D = B;

(void)A;
(void)D;
}


// Matches the example from clang/docs/SanitizerSpecialCaseList.rst
typedef char T;
typedef char U;
// TRUNC2-LABEL: docs_example
void docs_example(int toobig) {
// TRUNC2: %handler.implicit_conversion
T a = toobig;
// TRUNC2-NOT: %handler.implicit_conversion
U b = toobig;
// TRUNC2-NOT: %handler.implicit_conversion
char c = toobig;
}

2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
if(APPLE)
darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
endif()
list(REMOVE_ITEM ASAN_TEST_ARCH sparc sparcv9)
list(REMOVE_ITEM ASAN_TEST_ARCH sparcv9)
if(OS_NAME MATCHES "SunOS")
list(REMOVE_ITEM ASAN_TEST_ARCH x86_64)
endif()
Expand Down
9 changes: 8 additions & 1 deletion compiler-rt/lib/asan/tests/asan_oob_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"

#ifdef __sparc__
// Tests using unaligned accesses cannot work on strict-alignment targets.
#define SKIP_ON_STRICT_ALIGNMENT(x) DISABLED_##x
#else
#define SKIP_ON_STRICT_ALIGNMENT(x) x
#endif

NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
EXPECT_EQ(0U, ((uintptr_t)p % size));
if (size == 1) asan_write((uint8_t*)p);
Expand Down Expand Up @@ -79,7 +86,7 @@ TEST(AddressSanitizer, OOB_char) {
OOBTest<U1>();
}

TEST(AddressSanitizer, OOB_int) {
TEST(AddressSanitizer, SKIP_ON_STRICT_ALIGNMENT(OOB_int)) {
OOBTest<U4>();
}

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/tests/asan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {

#if !defined(__ANDROID__) && !defined(__arm__) && !defined(__aarch64__) && \
!defined(__mips__) && !defined(__mips64) && !defined(__s390__) && \
!defined(__riscv) && !defined(__loongarch__)
!defined(__riscv) && !defined(__loongarch__) && !defined(__sparc__)
NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
// create three red zones for these two stack objects.
int a;
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/asan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
if(APPLE)
darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
endif()
list(REMOVE_ITEM ASAN_TEST_ARCH sparc sparcv9)
list(REMOVE_ITEM ASAN_TEST_ARCH sparcv9)
if(OS_NAME MATCHES "SunOS")
list(REMOVE_ITEM ASAN_TEST_ARCH x86_64)
endif()
Expand Down
Loading

0 comments on commit 6e4861e

Please sign in to comment.