[Clang] Improve documentation for __builtin_allow_sanitize_check() (#175106)

Clarify that the builtin is intended for guarding explicit sanitizer
checks that use the runtime API to perform such checks. Update the
description to use "allowed" instead of "active" to better reflect the
intended usage and semantics, which would allow policy refinements in
future [1]. Also make the examples more concrete.

[1] https://discourse.llvm.org/t/explicit-sanitizer-checks-with-builtin-allow-sanitize-check/89383
This commit is contained in:
Marco Elver 2026-01-29 00:03:03 +01:00 committed by GitHub
parent 5b9751b99b
commit 913344bea1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 48 additions and 39 deletions

View File

@ -269,37 +269,40 @@ Interaction of Inlining with Disabling Sanitizer Instrumentation
#define ALWAYS_INLINE_IF_UNINSTRUMENTED __attribute__((always_inline))
#endif
Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
--------------------------------------------------------------------
Explicit Sanitizer Checks with ``__builtin_allow_sanitize_check``
-----------------------------------------------------------------
The ``__builtin_allow_sanitize_check("address")`` builtin can be used to
conditionally execute code only when AddressSanitizer is active for the current
function (after inlining). This is particularly useful for inserting explicit,
sanitizer-specific checks around operations like syscalls or inline assembly,
which might otherwise be unchecked by the sanitizer.
conditionally execute code depending on whether AddressSanitizer checks are
enabled and permitted by the current policy (after inlining). This is
particularly useful for inserting explicit, sanitizer-specific checks around
operations like syscalls or inline assembly, which might otherwise be unchecked
by the sanitizer.
Example:
.. code-block:: c
void __asan_load8(void *);
inline __attribute__((always_inline))
void copy_to_device(void *addr, size_t size) {
if (__builtin_allow_sanitize_check("address")) {
// Custom checks that address range is valid.
}
// ... actual device memory copy logic, potentially a syscall ...
void my_helper(void *addr) {
if (__builtin_allow_sanitize_check("address"))
__asan_load8(addr);
// ... actual logic, e.g. inline assembly ...
asm volatile ("..." : : "r" (addr) : "memory");
}
void instrumented_function() {
...
copy_to_device(buf, sizeof(buf)); // checks are active
my_helper(buf); // checks are active
...
}
__attribute__((no_sanitize("address")))
void uninstrumented_function() {
...
copy_to_device(buf, sizeof(buf)); // checks are skipped
my_helper(buf); // checks are skipped
...
}

View File

@ -117,37 +117,40 @@ Interaction of Inlining with Disabling Sanitizer Instrumentation
#define ALWAYS_INLINE_IF_UNINSTRUMENTED __attribute__((always_inline))
#endif
Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
--------------------------------------------------------------------
Explicit Sanitizer Checks with ``__builtin_allow_sanitize_check``
-----------------------------------------------------------------
The ``__builtin_allow_sanitize_check("memory")`` builtin can be used to
conditionally execute code only when MemorySanitizer is active for the current
function (after inlining). This is particularly useful for inserting explicit,
sanitizer-specific checks around operations like syscalls or inline assembly,
which might otherwise be unchecked by the sanitizer.
conditionally execute code depending on whether MemorySanitizer checks are
enabled and permitted by the current policy (after inlining). This is
particularly useful for inserting explicit, sanitizer-specific checks around
operations like syscalls or inline assembly, which might otherwise be unchecked
by the sanitizer.
Example:
.. code-block:: c
void __msan_check_mem_is_initialized(const void *, size_t);
inline __attribute__((always_inline))
void copy_to_device(void *addr, size_t size) {
if (__builtin_allow_sanitize_check("memory")) {
// Custom checks if `data` is initialized.
}
// ... actual device memory copy logic, potentially a syscall ...
void my_send(void *addr, size_t size) {
if (__builtin_allow_sanitize_check("memory"))
__msan_check_mem_is_initialized(addr, size);
// ... syscall or other logic where MSan may not see the access ...
send(addr, size);
}
void instrumented_function() {
...
copy_to_device(buf, sizeof(buf)); // checks are active
my_send(buf, sizeof(buf)); // checks are active
...
}
__attribute__((no_sanitize("memory")))
void uninstrumented_function() {
...
copy_to_device(buf, sizeof(buf)); // checks are skipped
my_send(buf, sizeof(buf)); // checks are skipped
...
}

View File

@ -126,37 +126,40 @@ Interaction of Inlining with Disabling Sanitizer Instrumentation
#define ALWAYS_INLINE_IF_UNINSTRUMENTED __attribute__((always_inline))
#endif
Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
--------------------------------------------------------------------
Explicit Sanitizer Checks with ``__builtin_allow_sanitize_check``
-----------------------------------------------------------------
The ``__builtin_allow_sanitize_check("thread")`` builtin can be used to
conditionally execute code only when ThreadSanitizer is active for the current
function (after inlining). This is particularly useful for inserting explicit,
sanitizer-specific checks around operations like syscalls or inline assembly,
which might otherwise be unchecked by the sanitizer.
conditionally execute code depending on whether ThreadSanitizer checks are
enabled and permitted by the current policy (after inlining). This is
particularly useful for inserting explicit, sanitizer-specific checks around
operations like syscalls or inline assembly, which might otherwise be unchecked
by the sanitizer.
Example:
.. code-block:: c
void __tsan_read8(void *);
inline __attribute__((always_inline))
void copy_to_device(void *addr, size_t size) {
if (__builtin_allow_sanitize_check("thread")) {
// Custom checks that `data` is not concurrently modified.
}
// ... actual device memory copy logic, potentially a syscall ...
void my_helper(void *addr) {
if (__builtin_allow_sanitize_check("thread"))
__tsan_read8(addr);
// ... actual logic, e.g. inline assembly ...
asm volatile ("..." : : "r" (addr) : "memory");
}
void instrumented_function() {
...
copy_to_device(&shared_data, size); // checks are active
my_helper(&shared_data); // checks are active
...
}
__attribute__((no_sanitize("thread")))
void uninstrumented_function() {
...
copy_to_device(&shared_data, size); // checks are skipped
my_helper(&shared_data); // checks are skipped
...
}