Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions clang/docs/AddressSanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ following types of bugs:
* Enable with: ``ASAN_OPTIONS=detect_stack_use_after_return=1`` (already enabled on Linux).
* Disable with: ``ASAN_OPTIONS=detect_stack_use_after_return=0``.
* Use-after-scope (clang flag ``-fsanitize-address-use-after-scope``)
* Container overflow detection (clang flag ``-fsanitize-address-disable-container-overflow`` to disable (experimental))
* Double-free, invalid free
* Memory leaks (experimental)

Expand Down Expand Up @@ -164,6 +165,23 @@ To summarize: ``-fsanitize-address-use-after-return=<mode>``
* ``always``: Enables detection of UAR errors in all cases. (reduces code
size, but not as much as ``never``).

Container Overflow Detection
----------------------------

AddressSanitizer can detect overflows in containers with custom allocators
(such as std::vector) where the Library developers have added calls into the
AddressSanitizer runtime to indicate which memory is poisoned etc.

In environments where not all the process binaries can be recompiled with
AddressSanitizer enabled, these checks can cause false positives.

These checks can be disabled at runtime using
``ASAN_OPTIONS=detect_container_overflow=0``

``-fsanitize-address-disable-container-overflow`` can be used at compile time
to disable container overflow checks if both the container and compiler support
the flag (experimental).

Memory leak detection
---------------------

Expand Down Expand Up @@ -242,6 +260,32 @@ AddressSanitizer also supports
works similar to ``__attribute__((no_sanitize("address")))``, but it also
prevents instrumentation performed by other sanitizers.

Disabling container overflow checks with ``__has_feature(sanitize_address_disable_container_overflow)``
-------------------------------------------------------------------------------------------------------

Library developers may use this feature test in conjunction with the
AddressSanitizer feature test to conditionally include container overflow
related code compiled into user code:

The recommended form is

.. code-block:: c

#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
// Container overflow detection enabled - include annotations
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid);
#endif

This pattern ensures that:

* Container overflow annotations are only included when AddressSanitizer is
enabled
* Container overflow detection can be disabled by
``-fsanitize-address-disable-container-overflow``
* Code compiles correctly with older compilers that don't support the
``sanitize_address_disable_container_overflow`` feature test (defaulting to
enabled container overflow checks)

Suppressing Errors in Recompiled Code (Ignorelist)
--------------------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5125,6 +5125,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
Select the mode of detecting stack use-after-return in AddressSanitizer: never | runtime (default) | always
-fsanitize-address-use-after-scope
Enable use-after-scope detection in AddressSanitizer
-fsanitize-address-disable-container-overflow
Disable container overflow detection at compile time in AddressSanitizer (experimental)
-fsanitize-address-use-odr-indicator
Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size
-fsanitize-ignorelist=<value>
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ CODEGENOPT(NewStructPathTBAA , 1, 0, Benign) ///< Whether or not to use enhanced
CODEGENOPT(SaveTempLabels , 1, 0, Benign) ///< Save temporary labels.
CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0, Benign) ///< Enable use-after-scope detection
///< in AddressSanitizer
CODEGENOPT(SanitizeAddressDisableContainerOverflow, 1, 0, Benign) ///< Disable container overflow checks
///< in AddressSanitizer
ENUM_CODEGENOPT(SanitizeAddressUseAfterReturn,
AsanDetectStackUseAfterReturnMode, 2,
AsanDetectStackUseAfterReturnMode::Runtime,
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ FEATURE(speculative_load_hardening, LangOpts.SpeculativeLoadHardening)
FEATURE(address_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress))
FEATURE(sanitize_address_disable_container_overflow,
LangOpts.SanitizeAddressDisableContainerOverflow)
FEATURE(leak_sanitizer,
LangOpts.Sanitize.has(SanitizerKind::Leak))
FEATURE(hwaddress_sanitizer,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety

LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")

LANGOPT(SanitizeAddressDisableContainerOverflow, 1, 0, NotCompatible,
"Disable container overflow checks in AddressSanitizer (experimental)")

#undef LANGOPT
#undef ENUM_LANGOPT
#undef VALUE_LANGOPT
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2512,6 +2512,12 @@ An operator new\[\] is "custom" if it is not one of the allocation functions
provided by the C++ standard library. Array cookies from non-custom allocation
functions are always poisoned.}]>,
Group<f_clang_Group>;
defm sanitize_address_disable_container_overflow : BoolOption<"f", "sanitize-address-disable-container-overflow",
CodeGenOpts<"SanitizeAddressDisableContainerOverflow">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Disable">,
NegFlag<SetFalse, [], [ClangOption], "Enable">,
BothFlags<[], [ClangOption], " container overflow checks in AddressSanitizer (experimental)">>,
Group<f_clang_Group>;
defm sanitize_address_globals_dead_stripping : BoolOption<"f", "sanitize-address-globals-dead-stripping",
CodeGenOpts<"SanitizeAddressGlobalsDeadStripping">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Enable linker dead stripping of globals in AddressSanitizer">,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class SanitizerArgs {
bool SharedRuntime = false;
bool StableABI = false;
bool AsanUseAfterScope = true;
bool AsanDisableContainerOverflow = false;
bool AsanPoisonCustomArrayCookie = false;
bool AsanGlobalsDeadStripping = false;
bool AsanUseOdrIndicator = false;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1131,8 +1131,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
AsanUseAfterScope = Args.hasFlag(
options::OPT_fsanitize_address_use_after_scope,
options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
AsanDisableContainerOverflow = Args.hasFlag(
options::OPT_fsanitize_address_disable_container_overflow,
options::OPT_fno_sanitize_address_disable_container_overflow,
AsanDisableContainerOverflow);
} else {
AsanUseAfterScope = false;
AsanDisableContainerOverflow = false;
}

if (AllAddedKinds & SanitizerKind::HWAddress) {
Expand Down Expand Up @@ -1459,6 +1464,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (AsanUseAfterScope)
CmdArgs.push_back("-fsanitize-address-use-after-scope");

if (AsanDisableContainerOverflow)
CmdArgs.push_back("-fsanitize-address-disable-container-overflow");

if (AsanPoisonCustomArrayCookie)
CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie");

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
LangOpts.ForceEmitVTables = CodeGenOpts.ForceEmitVTables;
LangOpts.SpeculativeLoadHardening = CodeGenOpts.SpeculativeLoadHardening;
LangOpts.CurrentModule = LangOpts.ModuleName;
LangOpts.SanitizeAddressDisableContainerOverflow =
CodeGenOpts.SanitizeAddressDisableContainerOverflow;

llvm::Triple T(TargetOpts.Triple);
llvm::Triple::ArchType Arch = T.getArch();
Expand Down
34 changes: 34 additions & 0 deletions clang/test/Driver/fsanitize-address-disable-container-overflow.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Test the -fsanitize-address-disable-container-overflow option

// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s \
// RUN: -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK-DEFAULT
// CHECK-DEFAULT-NOT: -fsanitize-address-disable-container-overflow

// RUN: %clang -target x86_64-linux-gnu -fsanitize=address \
// RUN: -fsanitize-address-disable-container-overflow %s -### 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-ENABLE %s
// CHECK-ENABLE: "-fsanitize-address-disable-container-overflow"

// RUN: %clang -target x86_64-linux-gnu -fsanitize=address \
// RUN: -fno-sanitize-address-disable-container-overflow %s -### 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-DISABLE %s
// CHECK-DISABLE-NOT: -fsanitize-address-disable-container-overflow

// RUN: %clang -target x86_64-linux-gnu -fsanitize=address \
// RUN: -fsanitize-address-disable-container-overflow \
// RUN: -fno-sanitize-address-disable-container-overflow %s -### 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-OVERRIDE %s
// CHECK-OVERRIDE-NOT: -fsanitize-address-disable-container-overflow

// Test that the flag generates unused warning without address sanitizer
// RUN: %clang -target x86_64-linux-gnu -fsanitize-address-disable-container-overflow %s \
// RUN: -### 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-NO-ASAN %s
// CHECK-NO-ASAN: warning: argument unused during compilation: '-fsanitize-address-disable-container-overflow'

// Test with kernel address sanitizer
// RUN: %clang -target x86_64-linux-gnu -fsanitize=kernel-address \
// RUN: -fsanitize-address-disable-container-overflow %s -### 2>&1 | \
// RUN: FileCheck -check-prefix=CHECK-KERNEL-ASAN %s
// CHECK-KERNEL-ASAN: "-fsanitize-address-disable-container-overflow"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %clang_cc1 -E -fsanitize=address %s -o - | FileCheck --check-prefix=CHECK-ASAN %s
// RUN: %clang_cc1 -E -fsanitize=address -fsanitize-address-disable-container-overflow %s -o - | FileCheck --check-prefix=CHECK-ASAN-DISABLE-CONTAINER %s
// RUN: %clang_cc1 -E -fsanitize=kernel-address -fsanitize-address-disable-container-overflow %s -o - | FileCheck --check-prefix=CHECK-ASAN-DISABLE-CONTAINER %s
// RUN: %clang_cc1 -E -fsanitize=address -fno-sanitize-address-disable-container-overflow %s -o - | FileCheck --check-prefix=CHECK-ASAN %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-ASAN %s

#if __has_feature(address_sanitizer)
int AddressSanitizerEnabled();
#else
int AddressSanitizerDisabled();
#endif

#if __has_feature(sanitize_address_disable_container_overflow)
int AddressSanitizerContainerOverflowDisabled();
#else
int AddressSanitizerContainerOverflowEnabled();
#endif

// CHECK-ASAN: AddressSanitizerEnabled
// CHECK-ASAN: AddressSanitizerContainerOverflowEnabled

// CHECK-ASAN-DISABLE-CONTAINER: AddressSanitizerEnabled
// CHECK-ASAN-DISABLE-CONTAINER: AddressSanitizerContainerOverflowDisabled

// CHECK-NO-ASAN: AddressSanitizerDisabled
// CHECK-NO-ASAN: AddressSanitizerContainerOverflowEnabled
20 changes: 20 additions & 0 deletions compiler-rt/test/asan/TestCases/contiguous_container_crash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,36 @@
// RUN: not %run %t odd-alignment-end 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
// RUN: %env_asan_opts=detect_container_overflow=0 %run %t crash
//
// Test with -fsanitize-address-disable-container-overflow flag - should not crash
// RUN: %clangxx_asan -fsanitize-address-disable-container-overflow -O %s -o %t-no-overflow
// RUN: %run %t-no-overflow crash
// RUN: %run %t-no-overflow bad-bounds
// RUN: %run %t-no-overflow unaligned-bad-bounds
// RUN: %run %t-no-overflow odd-alignment
// RUN: %run %t-no-overflow odd-alignment-end
//
// Test crash due to __sanitizer_annotate_contiguous_container.

#include <assert.h>
#include <string.h>

#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
extern "C" {
void __sanitizer_annotate_contiguous_container(const void *beg, const void *end,
const void *old_mid,
const void *new_mid);
} // extern "C"
#endif

static volatile int one = 1;

int TestCrash() {
long t[100];
t[60] = 0;
#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
__sanitizer_annotate_contiguous_container(&t[0], &t[0] + 100, &t[0] + 100,
&t[0] + 50);
#endif
// CHECK-CRASH: AddressSanitizer: container-overflow
// CHECK-CRASH: if you don't care about these errors you may set ASAN_OPTIONS=detect_container_overflow=0
return (int)t[60 * one]; // Touches the poisoned memory.
Expand All @@ -32,30 +44,38 @@ int TestCrash() {
void BadBounds() {
long t[100];
// CHECK-BAD-BOUNDS: ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container
#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
__sanitizer_annotate_contiguous_container(&t[0], &t[0] + 100, &t[0] + 101,
&t[0] + 50);
#endif
}

void UnalignedBadBounds() {
char t[100];
// CHECK-UNALIGNED-BAD-BOUNDS: ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container
#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
__sanitizer_annotate_contiguous_container(&t[1], &t[0] + 100, &t[0] + 101,
&t[0] + 50);
#endif
}

int OddAlignment() {
int t[100];
t[60] = 0;
#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
__sanitizer_annotate_contiguous_container(&t[1], &t[0] + 100, &t[0] + 100,
&t[1] + 50);
#endif
return (int)t[60 * one]; // Touches the poisoned memory.
}

int OddAlignmentEnd() {
int t[99];
t[60] = 0;
#if __has_feature(address_sanitizer) && !__has_feature(sanitize_address_disable_container_overflow)
__sanitizer_annotate_contiguous_container(&t[0], &t[0] + 98, &t[0] + 98,
&t[0] + 50);
#endif
return (int)t[60 * one]; // Touches the poisoned memory.
}

Expand Down
Loading