[PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap

0 views
Skip to first unread message

Kees Cook

unread,
Mar 31, 2026, 12:37:28 PM (10 days ago) Mar 31
to Peter Zijlstra, Kees Cook, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
From: Justin Stitt <justi...@google.com>

When CONFIG_OVERFLOW_BEHAVIOR_TYPES=y, Clang 23+'s Overflow Behavior
Type[1] annotations are available (i.e. __ob_trap, __ob_wrap). When not
enabled, these need to be empty macros. Document the new annotation and
add links from sanitizer docs pointing to the arithmetic-overflow docs.

Link: https://clang.llvm.org/docs/OverflowBehaviorTypes.html [1]
Signed-off-by: Justin Stitt <justi...@google.com>
Co-developed-by: Kees Cook <ke...@kernel.org>
Signed-off-by: Kees Cook <ke...@kernel.org>
---
Cc: Marco Elver <el...@google.com>
Cc: Andrey Konovalov <andre...@gmail.com>
Cc: Andrey Ryabinin <ryabin...@gmail.com>
Cc: Jonathan Corbet <cor...@lwn.net>
Cc: Shuah Khan <sk...@linuxfoundation.org>
Cc: Miguel Ojeda <oj...@kernel.org>
Cc: Nathan Chancellor <nat...@kernel.org>
Cc: <kasa...@googlegroups.com>
Cc: <linu...@vger.kernel.org>
Cc: <ll...@lists.linux.dev>
---
Documentation/dev-tools/ubsan.rst | 13 +
Documentation/process/arithmetic-overflow.rst | 323 ++++++++++++++++++
Documentation/process/deprecated.rst | 39 +++
Documentation/process/index.rst | 1 +
include/linux/compiler_attributes.h | 12 +
MAINTAINERS | 1 +
6 files changed, 389 insertions(+)
create mode 100644 Documentation/process/arithmetic-overflow.rst

diff --git a/Documentation/dev-tools/ubsan.rst b/Documentation/dev-tools/ubsan.rst
index e3591f8e9d5b..9e0c0f048eef 100644
--- a/Documentation/dev-tools/ubsan.rst
+++ b/Documentation/dev-tools/ubsan.rst
@@ -71,6 +71,19 @@ unaligned accesses (CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y). One could
still enable it in config, just note that it will produce a lot of UBSAN
reports.

+Additional sanitizer options include::
+
+ CONFIG_OVERFLOW_BEHAVIOR_TYPES=y
+
+This enables checking for integer arithmetic wrap-around (overflow/underflow).
+It instruments signed and unsigned integer overflow, as well as implicit
+truncation operations. This option is currently limited to specific types
+via the ``__ob_trap`` and ``__ob_wrap`` annotations.
+
+For detailed information about arithmetic overflow handling, overflow behavior
+annotations, and best practices, see:
+Documentation/process/arithmetic-overflow.rst
+
References
----------

diff --git a/Documentation/process/arithmetic-overflow.rst b/Documentation/process/arithmetic-overflow.rst
new file mode 100644
index 000000000000..2f19990f189b
--- /dev/null
+++ b/Documentation/process/arithmetic-overflow.rst
@@ -0,0 +1,323 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _arithmetic_overflow:
+
+Arithmetic Overflow Resolutions for Linux
+=========================================
+
+Background
+----------
+
+When a calculation's result exceeds the involved storage ranges, several
+strategies can be followed to handle such an overflow (or underflow),
+including:
+
+ - Undefined (i.e. pretend it's impossible and the result depends on hardware)
+ - Wrap around (this is what 2s-complement representation does by default)
+ - Trap (create an exception so the problem can be handled in another way)
+ - Saturate (explicitly hold the maximum or minimum representable value)
+
+In the C standard, three basic types can be involved in arithmetic, and each
+has a default strategy for solving the overflow problem:
+
+ - Signed overflow is undefined
+ - Unsigned overflow explicitly wraps around
+ - Pointer overflow is undefined
+
+The Linux kernel uses ``-fno-strict-overflow`` which implies ``-fwrapv``
+and ``-fwrapv-pointer`` which treats signed integer overflow and pointer
+overflow respectively as being consistent with two's complement. This flag
+allows for consistency within the codebase about the expectations of
+overflowing arithmetic as well as prevents eager compiler optimizations.
+Note that :ref:`open-coded intentional arithmetic wrap-around is deprecated <open_coded_wrap_around>`.
+
+From here on, arithmetic overflow concerning signed, unsigned, or
+pointer types will be referred to as "wrap-around" since it is the
+default strategy for the kernel. There is no such thing as "undefined
+behavior" for arithmetic in Linux: it always wraps.
+
+Overflow Behavior Types
+-----------------------
+
+The newly available ``__ob_trap`` and ``__ob_wrap`` annotations provide
+fine-grained control over overflow behavior. These can be applied to
+integer types to unambiguously specify how arithmetic operations are
+expected to behave upon overflow. Currently, only Clang supports these
+annotations. The annotation defines two possible overflow behaviors:
+
+* ``wrap``: Ensures arithmetic operations wrap on overflow, providing
+ well-defined two's complement semantics according to the bitwidth of the
+ underlying type, regardless of any associated ``-fwrapv`` options or
+ sanitizers (integer overflow and truncation checks are suppressed)
+* ``trap``: Enables overflow and truncation checking for the type, even when
+ associated ``-fwrapv`` options are enabled. Without the sanitizer enabled
+ the compiler emits a trap instruction, otherwise the integer overflow
+ and truncation warnings are emitted but execution continues.
+
+Note that the sanitizer infrastructure is used for instrumentation shows
+up in logs as the "Undefined Behavior" sanitizer (UBSan), which may be
+confusing. Instead this should be thought of as the "Unexpected Behavior"
+sanitizer. Its infrastructure is used to report on unexpected wrapping
+behaviors: none of integer operations are "undefined" any more, as per
+the use of ``-fno-strict-overflow``, but instead UBSan will kick in when
+a type is explicitly marked as non-wrapping (i.e. trapping).
+
+
+Enablement
+~~~~~~~~~~
+
+When supported by the compiler, kernels can build with either
+``CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP=y`` for trapping mode (i.e.
+mitigation enabled), or ``CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN=y`` which
+enables warn-only mode, which logs the overflows but will continue as
+if the type was not marked with ``__ob_trap``.
+
+Compiler Options
+^^^^^^^^^^^^^^^^
+
+Usage of the ``overflow_behavior`` attribute is gated behind the
+``-fexperimental-overflow-behavior-types`` compiler flag which
+is a ``-cc1`` flag, meaning the kernel passes it as ``-Xclang
+-fexperimental-overflow-behavior-types``.
+
+Sanitizer Case Lists
+^^^^^^^^^^^^^^^^^^^^
+
+Linux uses a Sanitizer Case List file to selectively enable certain
+sanitizers for specific types. Specifically, the overflow and truncation
+sanitizers have had their standard instrumentation disabled for all
+types. To "allowlist" specific types for instrumentation the kernel
+makes use of the in-source ``__ob_trap`` annotations to gain reporting
+by the sanitizers.
+
+Currently, type-based entries within a sanitizer case list are only
+supported by Clang. For more information on the syntax for SCL files
+refer to the Clang docs:
+https://clang.llvm.org/docs/SanitizerSpecialCaseList.html
+
+Syntax
+~~~~~~
+
+Creating Overflow Behavior Types is possible via two syntactic forms;
+
+**Attribute syntax:**
+
+.. code-block:: c
+
+ typedef unsigned int __attribute__((overflow_behavior(trap))) safe_uint;
+ typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;
+
+**Keyword syntax:**
+
+.. code-block:: c
+
+ typedef unsigned int __ob_trap safe_uint;
+ typedef unsigned int __ob_wrap wrapping_uint;
+
+Both forms are semantically identical. The keyword syntax is shorter and can
+appear in the same positions as ``const`` or ``volatile``. The attribute syntax
+is more self-documenting, so Linux uses this form.
+
+When ``-fexperimental-overflow-behavior-types`` is not enabled, both the
+keywords (``__ob_wrap``, ``__ob_trap``) and the attribute are ignored with a
+warning.
+
+The feature can be queried with either
+``__has_extension(overflow_behavior_types)`` or
+``__has_attribute(overflow_behavior)``.
+
+Basic Usage
+^^^^^^^^^^^
+
+.. code-block:: c
+
+ typedef unsigned int __ob_wrap counter_t;
+ typedef unsigned long __ob_trap safe_size_type;
+
+ counter_t increment_counter(counter_t count) {
+ return count + 1;
+ }
+
+ safe_size_type calculate_buffer_size(safe_size_type base,
+ safe_size_type extra) {
+ return base + extra;
+ }
+
+In the first function, arithmetic on ``counter_t`` is well-defined
+wrapping. Its overflow will never be reported and unlike an plain
+``unsigned int`` its purpose is unambiguous: it is expected to wrap
+around. In the second function, arithmetic on ``safe_size_type`` is
+checked -- overflow will result in a trap or sanitizer report depending
+on the build configuration.
+
+Variables can be annotated directly:
+
+.. code-block:: c
+
+ void foo(int num) {
+ int __ob_trap a = num;
+ a += 42;
+
+ unsigned char __ob_wrap b = 255;
+ b += 10;
+ }
+
+
+Interaction with Compiler Options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Overflow behavior annotations override many global compiler flags and
+sanitizer configurations:
+
+* ``wrap`` types suppress UBSan's integer overflow checks
+ (``signed-integer-overflow``, ``unsigned-integer-overflow``) and implicit
+ truncation checks (``implicit-signed-integer-truncation``,
+ ``implicit-unsigned-integer-truncation``). They also suppress ``-ftrapv``
+ for the annotated type.
+* ``trap`` types enable overflow checking even when ``-fwrapv``
+ is globally enabled. When no sanitizer runtime is available, the compiler
+ emits a trap instruction directly.
+* Both forms override Sanitizer Special Case List (SSCL) entries.
+
+Common overflow idioms are excluded from instrumentation via
+``-fsanitize-undefined-ignore-overflow-pattern=``. These overflow idioms have
+their instrumentation withheld even under the presence of overflow behavior
+annotations. For more details see:
+https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#disabling-instrumentation-for-common-overflow-patterns
+
+Truncation Semantics
+^^^^^^^^^^^^^^^^^^^^
+
+Truncation and overflow are related -- both are often desirable in some
+contexts and undesirable in others. Overflow behavior types control truncation
+instrumentation at the type level as well:
+
+* If a ``trap`` type is involved as source or destination of a truncation, the
+ compiler inserts truncation checks. These will either trap or report via
+ sanitizer depending on the build configuration.
+* If a ``wrap`` type is involved as source or destination, truncation checks
+ are suppressed regardless of compiler flags.
+* If both ``trap`` and ``wrap`` are involved in the same truncation, ``wrap``
+ takes precedence (truncation checks are suppressed) since the explicit
+ wrapping intent covers truncation as well.
+
+.. code-block:: c
+
+ void checked(char a, int __ob_trap b) {
+ a = b;
+ }
+
+ void wrapping(char a, int __ob_wrap b) {
+ a = b;
+ }
+
+
+Promotion Rules
+^^^^^^^^^^^^^^^
+
+Overflow behavior types follow standard C integer promotion rules while
+preserving the overflow behavior annotation through expressions:
+
+* When an overflow behavior type is mixed with a standard integer type, the
+ result carries the overflow behavior annotation. Standard C conversion rules
+ determine the resulting width and signedness.
+* When two overflow behavior types of the same kind (both ``wrap`` or both
+ ``trap``) are mixed, the result follows standard C arithmetic conversion
+ rules with that behavior applied.
+* When ``wrap`` and ``trap`` are mixed, ``trap`` dominates. The result follows
+ standard C conversions with ``trap`` behavior.
+
+.. code-block:: c
+
+ typedef int __ob_wrap wrap_int;
+ typedef int __ob_trap trap_int;
+
+ wrap_int a = 1;
+ trap_int b = 2;
+ /* a + b results in __ob_trap int (trap dominates) */
+
+
+Type Compatibility
+^^^^^^^^^^^^^^^^^^
+
+Overflow behavior types are distinct from their underlying types for type
+checking purposes. Assigning between types with different overflow behaviors
+(``wrap`` vs ``trap``) is an error:
+
+.. code-block:: c
+
+ int __ob_wrap w;
+ int __ob_trap t;
+ w = t; /* error: incompatible overflow behavior types */
+
+Assigning from an overflow behavior type to a plain integer type discards the
+overflow behavior. The compiler can warn about this with
+``-Wimplicit-overflow-behavior-conversion`` (implied by ``-Wconversion``).
+
+Intentionally discarding the overflow behavior should use an explicit
+cast:
+
+.. code-block:: c
+
+ unsigned long __ob_trap checked_size;
+ unsigned long regular_size;
+
+ regular_size = checked_size; /* warning: discards overflow behavior */
+ regular_size = (unsigned long)checked_size; /* OK, explicit cast */
+
+If truncation should be allowed for a cast away from ``trap``, an
+explicit ``wrap`` cast is needed to suppress run-time instrumentation:
+
+.. code-block:: c
+
+ unsigned long __ob_trap checked_size;
+ unsigned char small_size;
+
+ small_size = checked_size; /* may trap at run-time on truncation */
+ small_size = (unsigned long __ob_wrap)checked_size; /* OK, explicit cast */
+
+
+Pointer Semantics
+^^^^^^^^^^^^^^^^^
+
+Pointers to overflow behavior types are treated as distinct from pointers to
+their underlying types. Converting between them produces a warning controlled
+by ``-Wincompatible-pointer-types-discards-overflow-behavior``:
+
+.. code-block:: c
+
+ unsigned long *px;
+ unsigned long __ob_trap *py;
+
+ px = py; /* warning: discards overflow behavior */
+ py = px; /* warning: discards overflow behavior */
+
+
+Best Practices
+^^^^^^^^^^^^^^
+
+1. **Use ``__ob_trap`` for sizes and counts** where overflow indicates bugs:
+
+ .. code-block:: c
+
+ typedef unsigned long long __ob_trap no_wrap_u64;
+ no_wrap_u64 buffer_len = kmalloc_size + header_size;
+
+2. **Use ``__ob_wrap`` for arithmetic that intentionally overflows**:
+
+ .. code-block:: c
+
+ typedef u32 __ob_wrap hash_t;
+ hash_t hash = (hash * 31) + byte;
+
+3. **Don't mix different overflow behavior types**:
+
+ .. code-block:: c
+
+ int __ob_wrap a;
+ int __ob_trap b;
+
+ a = b; /* error: incompatible overflow behavior types */
+
+ a = (int __ob_wrap)b; /* OK, explicit cast */
+ a = (int)b; /* OK, cast to underlying type */
diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index fed56864d036..1c20f7ff0798 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -109,6 +109,45 @@ For more details, also see array3_size() and flex_array_size(),
as well as the related check_mul_overflow(), check_add_overflow(),
check_sub_overflow(), and check_shl_overflow() family of functions.

+.. _open_coded_wrap_around:
+
+open-coded intentional arithmetic wrap-around
+---------------------------------------------
+Depending on arithmetic wrap-around without annotations means the
+kernel cannot distinguish between intentional wrap-around and accidental
+wrap-around (when using things like the overflow sanitizers).
+
+For example, where an addition is intended to wrap around::
+
+ magic = counter + rotation;
+
+please use the wrapping_add() helper::
+
+ magic = wrapping_add(int, counter, rotation);
+
+To help minimize needless code churn, the kernel uses overflow idiom exclusions
+(currently only supported by Clang). Some commonly used overflow-dependent code
+patterns will not be instrumented by overflow sanitizers. The currently
+supported patterns are::
+
+ /* wrap-around test */
+ if (var + offset < var) ...
+
+ /* standalone unsigned decrement used in while loop */
+ while(size--)
+
+ /* negated unsigned constants */
+ -1UL;
+ -5U;
+
+In rare cases where helpers aren't available (e.g. in early boot code, etc) but
+overflow instrumentation still needs to be avoided, utilize wrap-around tests
+to check wrap-around outcomes before performing calculations::
+
+ if (var + offset < var) {
+ /* wrap-around has occurred */
+ }
+
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
The simple_strtol(), simple_strtoll(),
diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst
index dbd6ea16aca7..620257eca00e 100644
--- a/Documentation/process/index.rst
+++ b/Documentation/process/index.rst
@@ -111,3 +111,4 @@ developers:

kernel-docs
deprecated
+ arithmetic-overflow
diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
index c16d4199bf92..65f57ff378bb 100644
--- a/include/linux/compiler_attributes.h
+++ b/include/linux/compiler_attributes.h
@@ -396,6 +396,18 @@
# define __disable_sanitizer_instrumentation
#endif

+/*
+ * Optional: only supported by Clang with -Xclang -experimental-foverflow-behavior-types
+ * passed via CONFIG_OVERFLOW_BEHAVIOR_TYPES. When not available, define empty macros for
+ * the trap/wrap annotations.
+ *
+ * clang: https://clang.llvm.org/docs/OverflowBehaviorTypes.html
+ */
+#if !__has_attribute(overflow_behavior) || !defined(OVERFLOW_BEHAVIOR_TYPES)
+# define __ob_trap
+# define __ob_wrap
+#endif
+
/*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-weak-function-attribute
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-weak-variable-attribute
diff --git a/MAINTAINERS b/MAINTAINERS
index a9f067164203..342a550c25b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19925,6 +19925,7 @@ M: Justin Stitt <justi...@google.com>
L: linux-h...@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
+F: Documentation/process/arithmetic-overflow.rst
F: scripts/integer-wrap-ignore.scl
F: scripts/Makefile.obt

--
2.34.1

Miguel Ojeda

unread,
Mar 31, 2026, 1:02:10 PM (10 days ago) Mar 31
to Kees Cook, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, Mar 31, 2026 at 6:37 PM Kees Cook <ke...@kernel.org> wrote:
>
> +/*
> + * Optional: only supported by Clang with -Xclang -experimental-foverflow-behavior-types
> + * passed via CONFIG_OVERFLOW_BEHAVIOR_TYPES. When not available, define empty macros for
> + * the trap/wrap annotations.
> + *
> + * clang: https://clang.llvm.org/docs/OverflowBehaviorTypes.html
> + */
> +#if !__has_attribute(overflow_behavior) || !defined(OVERFLOW_BEHAVIOR_TYPES)
> +# define __ob_trap
> +# define __ob_wrap
> +#endif

Should that have `CONFIG_*`? i.e.

!defined(CONFIG_OVERFLOW_BEHAVIOR_TYPES)

In addition, since this depends on a `CONFIG_`, with the current setup
we would put them elsewhere instead of `compiler_attributes.h` until
they are promoted to be "unconditional" (i.e. without the compiler
flag):

* Any other "attributes" (i.e. those that depend on a configuration option,
* on a compiler, on an architecture, on plugins, on other attributes...)
* should be defined elsewhere (e.g. compiler_types.h or compiler-*.h).
* The intention is to keep this file as simple as possible, as well as
* compiler- and version-agnostic (e.g. avoiding GCC_VERSION checks).

However, thinking about it, why is the config needed?

i.e. if the compiler is not passed that flag, shouldn't the
`__has_attribute` simply return false?

Also, I am a bit confused -- does the compiler flag automatically
recognize the names like `__ob_trap`? i.e. I see the docs mention
using the attribute,

typedef unsigned int __attribute__((overflow_behavior(trap))) safe_uint;
typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;

But then we don't actually use it?

Or should this just be like the rest of the attributes, i.e. we
actually define them here?

Thanks!

Cheers,
Miguel

Miguel Ojeda

unread,
Mar 31, 2026, 1:09:28 PM (10 days ago) Mar 31
to Kees Cook, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, Mar 31, 2026 at 7:01 PM Miguel Ojeda
<miguel.oje...@gmail.com> wrote:
>
> Also, I am a bit confused -- does the compiler flag automatically
> recognize the names like `__ob_trap`? i.e. I see the docs mention
> using the attribute,
>
> typedef unsigned int __attribute__((overflow_behavior(trap))) safe_uint;
> typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;
>
> But then we don't actually use it?

Ah, it does, it is a keyword, and I should have read the docs better.

From a quick test in Compiler Explorer it seems to be fine to define a
macro like the keyword:

#define __ob_trap __attribute__((overflow_behavior(trap)))
#define __ob_wrap __attribute__((overflow_behavior(wrap)))

That could be a bit more flexible in the name we pick on our side and
more like the rest of the attributes, but if the intention is to
eventually use that keyword in standard C or similar, I guess it is
fine.

Cheers,
Miguel

Justin Stitt

unread,
Mar 31, 2026, 1:09:47 PM (10 days ago) Mar 31
to Miguel Ojeda, Kees Cook, Peter Zijlstra, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Hi,
__ob_trap and __ob_wrap are defined by the compiler.

There are some examples within the documentation additions of this patch.

Kees, is it possible to make it more clear about what we expect of
kernel developers in terms of style? Should they use keyword
spellings? attribute spellings? only use custom types?

>
> Or should this just be like the rest of the attributes, i.e. we
> actually define them here?
>
> Thanks!
>
> Cheers,
> Miguel

Justin

Miguel Ojeda

unread,
Mar 31, 2026, 1:14:52 PM (10 days ago) Mar 31
to Justin Stitt, Kees Cook, Peter Zijlstra, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, Mar 31, 2026 at 7:09 PM Justin Stitt <justi...@google.com> wrote:
>
> __ob_trap and __ob_wrap are defined by the compiler.
>
> There are some examples within the documentation additions of this patch.
>
> Kees, is it possible to make it more clear about what we expect of
> kernel developers in terms of style? Should they use keyword
> spellings? attribute spellings? only use custom types?

Yeah, I noticed that right after sending the email, sorry.

So I tried to use a macro even if happens to have the same name as the
keyword, since that form is a bit more flexible, but it is fine either
way.

What I would suggest is adding to the comment that these were decided
to be used as keywords, and thus we only need to define them as empty
in the disabled case.

Thanks!

Cheers,
Miguel

Linus Torvalds

unread,
Mar 31, 2026, 1:17:12 PM (10 days ago) Mar 31
to Kees Cook, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, 31 Mar 2026 at 09:37, Kees Cook <ke...@kernel.org> wrote:
>> +
> + typedef unsigned int __attribute__((overflow_behavior(trap))) safe_uint;
> + typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;

This is fundamentally broken sh*t.

Stop thinking that trapping is "safe".

It damn well isn't. A dead machine is not a safe machine.

Any patches that call trapping behavior safe will ne NAK'ed by me.,

We have decades of peoiple using BUG_ON() as a safety measure, and it
has been a HUGE PROBLEM.

There is no way in hell that we are ever adding implicit BUG_ON()
things that are this hidden, this easy to use, and then mislabeled as
being "safe".

Guys, that's the same logic as having a airbag in your car that just
shoots you in the head. You're certainly "safe" from the vagaries of
bad healthcare. But dammit, if anybody thinks that a "bullet to the
head" should be called "safe", then that person damn well shouldn't be
involved with kernel development.

So NAK NAK NAK NAK.

The only safe trapping behavior is something that has a clear an
unambiguous and simple to use way to *HANDLE* it. Not just "mark it
trapping".

Linus

Justin Stitt

unread,
Mar 31, 2026, 1:18:00 PM (10 days ago) Mar 31
to Miguel Ojeda, Kees Cook, Peter Zijlstra, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Hi,
Agreed.

>
> Thanks!
>
> Cheers,
> Miguel

Justin

Linus Torvalds

unread,
Mar 31, 2026, 1:26:08 PM (10 days ago) Mar 31
to Kees Cook, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, 31 Mar 2026 at 10:16, Linus Torvalds
<torv...@linux-foundation.org> wrote:
>
> The only safe trapping behavior is something that has a clear an
> unambiguous and simple to use way to *HANDLE* it. Not just "mark it
> trapping".

Side note: this is the same kind of complete and utter idiocy that
made Rust people have allocators that abort when running out of
memory, because it's "safer" than returning NULL.

THAT KIND OF THINKING IS NOT ACCEPTABLE IN THE KERNEL.

I don't know why people keep doing this. Stop it.

Linus

Kees Cook

unread,
Mar 31, 2026, 3:52:12 PM (9 days ago) Mar 31
to Justin Stitt, Miguel Ojeda, Peter Zijlstra, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
I think for this series, __ob_trap/__ob_wrap is what should be used.

And for other folks, the background here is that we originally wanted
to use macros for "__trap" and "__wrap", but the powerpc C compiler
(both Clang and GCC) have a builtin macro named "__trap" already. So
I switched to just using the Clang-native type qualifier. We can use
the attribute style too, but there was a lot of confusion during the
Clang development phases where people kept forgetting this was a type
qualifier, not an attribute (i.e. the attribute is an internal alias
for the qualifier, and the qualifier is a new type).

--
Kees Cook

Vincent Mailhol

unread,
Apr 1, 2026, 3:20:05 AM (9 days ago) Apr 1
to Kees Cook, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Hi Kees,

Many thanks for this series. Great work and I am ready it with a lot of
interest!
I just wanted to ask how much consideration was put into this last
"saturate" option.

When speaking of "safe" as in "functional safety" this seems a good
option to me. The best option is of course proper handling, but as
discussed, we are speaking of the scenario in which the code is already
buggy and which is the fallout option doing the least damage.

What I have in mind is a new __ob_saturate type qualifier. Something like:

void foo(int num)
{
int __ob_saturate saturate_var = num;

saturate_var += 42;
}

would just print a warning and continue execution, thus solving the
trapping issue. The above code would generate something equivalent to that:

void foo(int num)
{
int __ob_saturate saturate_var = num;

if (check_add_overflow(saturate_var, increment,
&saturate_var) {
WARN(true, "saturation occurred");
saturate_var = type_max(saturate_var);
}

People using those saturating integers could then later check that the
value is still in bound.

This is basically what your size_add() from overflow.h is already doing.
If an overflow occurred, the allocation the addition does not trap, it
just saturates and let the allocation functions properly handle the issue.

The saturation can neutralize many security attacks and can mitigate
some safety issues. Think of the Ariane 5 rocket launch: a saturation
could have prevented the unintended fireworks.

The caveat I can think of is that the old overflow check pattern becomes
invalid. Doing:

if (saturate_var + increment < increment)

is now bogus and would need to be caught if possible by static analysis.
So those saturating integers will only be usable in newly written code
and could not be easily retrofitted.

> +In the C standard, three basic types can be involved in arithmetic, and each
> +has a default strategy for solving the overflow problem:
> +
> + - Signed overflow is undefined
> + - Unsigned overflow explicitly wraps around
> + - Pointer overflow is undefined

Nitpick: the C standard uses different definitions than yours. In the
standard:

- overflow is *always* undefined
- unsigned integer wraparound
- signed integer overflow

The nuance is that in the standard unsigned integers do not overflow,
they just wraparound.

I am not asking you to change your terminology, but it could be good to
state in your document that your definition of overflow differs from the
standard's definition. Maybe a terminology section could help.


Yours sincerely,
Vincent Mailhol

Peter Zijlstra

unread,
Apr 1, 2026, 5:08:28 AM (9 days ago) Apr 1
to Kees Cook, Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Tue, Mar 31, 2026 at 12:52:10PM -0700, Kees Cook wrote:

> I think for this series, __ob_trap/__ob_wrap is what should be used.
>
> And for other folks, the background here is that we originally wanted
> to use macros for "__trap" and "__wrap", but the powerpc C compiler
> (both Clang and GCC) have a builtin macro named "__trap" already. So
> I switched to just using the Clang-native type qualifier. We can use
> the attribute style too, but there was a lot of confusion during the
> Clang development phases where people kept forgetting this was a type
> qualifier, not an attribute (i.e. the attribute is an internal alias
> for the qualifier, and the qualifier is a new type).

Since you mention qualifiers...

What is the result of __typeof_unqual__(int __ob_trap) ?

Peter Zijlstra

unread,
Apr 1, 2026, 5:20:50 AM (9 days ago) Apr 1
to Vincent Mailhol, Kees Cook, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Wed, Apr 01, 2026 at 09:19:51AM +0200, Vincent Mailhol wrote:
> Le 31/03/2026 à 18:37, Kees Cook a écrit :

> > + - Saturate (explicitly hold the maximum or minimum representable value)
>
> I just wanted to ask how much consideration was put into this last
> "saturate" option.
>
> When speaking of "safe" as in "functional safety" this seems a good
> option to me. The best option is of course proper handling, but as
> discussed, we are speaking of the scenario in which the code is already
> buggy and which is the fallout option doing the least damage.
>
> What I have in mind is a new __ob_saturate type qualifier. Something like:
>
> void foo(int num)
> {
> int __ob_saturate saturate_var = num;
>
> saturate_var += 42;
> }
>
> would just print a warning and continue execution, thus solving the
> trapping issue. The above code would generate something equivalent to that:
>
> void foo(int num)
> {
> int __ob_saturate saturate_var = num;
>
> if (check_add_overflow(saturate_var, increment,
> &saturate_var) {
> WARN(true, "saturation occurred");
> saturate_var = type_max(saturate_var);
> }

So I would like to second this option as being interesting.

But while pondering it, I did want to note that all of the options, with
the exception of __ob_wrap (which is effectively what we have today for
*everything*), will be 'interesting' to compose with _Atomic, another
one of these qualifiers.

Now, in the kernel we don't use _Atomic, so strictly speaking I don't
care ;-) But here goes...

Something like _Atomic int __ob_wrap, is trivial and good.

_Atomic int __ob_trap is either doable or impossible depending on how
you define the result to be on 'trap'. Specifically, the semantics
proposed where it keeps the old value makes it impossible.

And _Atomic int __ob_saturate is equally 'challenging', since the
fundamental thing of 'reset to min/max on under/over-flow' is rather
a non-atomic kind of thing. Look at the trouble we went through with
refcount_t to sort of make this work.

Kees Cook

unread,
Apr 1, 2026, 3:42:05 PM (8 days ago) Apr 1
to Vincent Mailhol, Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
On Wed, Apr 01, 2026 at 09:19:51AM +0200, Vincent Mailhol wrote:
> Many thanks for this series. Great work and I am ready it with a lot of
> interest!

Yay! Glad to have folks looking at it all.

> I just wanted to ask how much consideration was put into this last
> "saturate" option.
>
> When speaking of "safe" as in "functional safety" this seems a good
> option to me. The best option is of course proper handling, but as
> discussed, we are speaking of the scenario in which the code is already
> buggy and which is the fallout option doing the least damage.

Right -- harm reduction. :)

> What I have in mind is a new __ob_saturate type qualifier. Something like:
>
> void foo(int num)
> {
> int __ob_saturate saturate_var = num;
>
> saturate_var += 42;
> }
>
> would just print a warning and continue execution, thus solving the
> trapping issue. The above code would generate something equivalent to that:
>
> void foo(int num)
> {
> int __ob_saturate saturate_var = num;
>
> if (check_add_overflow(saturate_var, increment,
> &saturate_var) {
> WARN(true, "saturation occurred");
> saturate_var = type_max(saturate_var);
> }

Right, yes. Note that __ob_saturate is entirely unimplemented, but we
wanted to leave the door open for other Overflow Behaviors. (It was
tricky enough to even get the semantics worked out from wrap and trap,
so we wanted to get to a distinct first step landed first.)

For the "warn" part with __ob_trap, we borrowed the Sanitizer
infrastructure since architecturally it's in exactly the same places
that __ob_trap needs to be checking, and already has everything
available. In the case of __ob_saturate, it would only be informational.
(Arguably, there should be no "warn" at all, as it's the "expected"
behavior, just like __ob_wrap has no "warn" on wrap-around. But it seems
sensible to me to make that available by enabling the sanitizers too.)

> People using those saturating integers could then later check that the
> value is still in bound.
>
> This is basically what your size_add() from overflow.h is already doing.
> If an overflow occurred, the allocation the addition does not trap, it
> just saturates and let the allocation functions properly handle the issue.

Right.

> The saturation can neutralize many security attacks and can mitigate
> some safety issues. Think of the Ariane 5 rocket launch: a saturation
> could have prevented the unintended fireworks.
>
> The caveat I can think of is that the old overflow check pattern becomes
> invalid. Doing:
>
> if (saturate_var + increment < increment)
>
> is now bogus and would need to be caught if possible by static analysis.
> So those saturating integers will only be usable in newly written code
> and could not be easily retrofitted.

In theory, the "ignored patterns" (or "idiom exclusions") would already
allow this to continue to behave correctly, though it may be worth trying
to figure out if this is "correct" or not.

> > +In the C standard, three basic types can be involved in arithmetic, and each
> > +has a default strategy for solving the overflow problem:
> > +
> > + - Signed overflow is undefined
> > + - Unsigned overflow explicitly wraps around
> > + - Pointer overflow is undefined
>
> Nitpick: the C standard uses different definitions than yours. In the
> standard:
>
> - overflow is *always* undefined
> - unsigned integer wraparound
> - signed integer overflow
>
> The nuance is that in the standard unsigned integers do not overflow,
> they just wraparound.

I guess that's technically true, but for understanding the "overflow
resolution" properties (from a mathematical perspective), the question
is "what happens when a value cannot be represented by the bit pattern
of the storage?" But I think we understand each other here. :)
So given that under C, signed is undefined and unsigned in wraparound,
this is how we ended up phrasing it.

> I am not asking you to change your terminology, but it could be good to
> state in your document that your definition of overflow differs from the
> standard's definition. Maybe a terminology section could help.

I'm open to whatever you think would make this more clear. :)

-Kees

--
Kees Cook

Kees Cook

unread,
Apr 1, 2026, 3:44:01 PM (8 days ago) Apr 1
to Peter Zijlstra, Vincent Mailhol, Justin Stitt, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Yeah, this is mainly why we didn't spend time working on an
__ob_saturate implementation: the primary place we want it in Linux is
already solved with all the refcount_t work. That said, if the behavior
could be replicated using a future __ob_saturate, that would be very
nice. :)

--
Kees Cook

Kees Cook

unread,
Apr 1, 2026, 4:21:19 PM (8 days ago) Apr 1
to Peter Zijlstra, Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Hmm, it seems like "const" doesn't get peeled off. That can be fixed, if
that's needed?

'typeof_unqual(int)' (aka 'int')
'typeof_unqual(__ob_trap int)' (aka '__ob_trap int')
'typeof_unqual(const int)' (aka 'int')
'typeof_unqual(__ob_trap const int)' (aka '__ob_trap const int')

-Kees

--
Kees Cook

Peter Zijlstra

unread,
Apr 1, 2026, 4:31:06 PM (8 days ago) Apr 1
to Kees Cook, Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
So how can something be called a qualifier if unqual doesn't strip it?

(We might already have had this discussion, but I can't find the answer
in the LLVM documentation page and didn't search our previous
correspondence on this).

Kees Cook

unread,
Apr 1, 2026, 4:55:44 PM (8 days ago) Apr 1
to Peter Zijlstra, Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
I'll let Justin answer this correctly, but I suspect I'm using the wrong
name for things. I think I should have said "keyword"? The mechanism
produces a distinct type, so it's not actually a "qualifier", but the
intent is that they are distinct types (this came from a long long
discussion with the LLVM devs, etc), but that they have implicit casts
to the non-obt scalars, but Justin knows more on this.

--
Kees Cook

Justin Stitt

unread,
Apr 1, 2026, 7:43:06 PM (8 days ago) Apr 1
to Peter Zijlstra, Kees Cook, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Hi,

On Wed, Apr 1, 2026 at 1:31 PM Peter Zijlstra <pet...@infradead.org> wrote:
>
> On Wed, Apr 01, 2026 at 01:21:17PM -0700, Kees Cook wrote:
> > On Wed, Apr 01, 2026 at 11:08:15AM +0200, Peter Zijlstra wrote:
> > > On Tue, Mar 31, 2026 at 12:52:10PM -0700, Kees Cook wrote:
> > >
> > > > I think for this series, __ob_trap/__ob_wrap is what should be used.
> > > >
> > > > And for other folks, the background here is that we originally wanted
> > > > to use macros for "__trap" and "__wrap", but the powerpc C compiler
> > > > (both Clang and GCC) have a builtin macro named "__trap" already. So
> > > > I switched to just using the Clang-native type qualifier. We can use
> > > > the attribute style too, but there was a lot of confusion during the
> > > > Clang development phases where people kept forgetting this was a type
> > > > qualifier, not an attribute (i.e. the attribute is an internal alias
> > > > for the qualifier, and the qualifier is a new type).
> > >
> > > Since you mention qualifiers...
> > >
> > > What is the result of __typeof_unqual__(int __ob_trap) ?
> >
> > Hmm, it seems like "const" doesn't get peeled off. That can be fixed, if
> > that's needed?
> >
> > 'typeof_unqual(int)' (aka 'int')
> > 'typeof_unqual(__ob_trap int)' (aka '__ob_trap int')
> > 'typeof_unqual(const int)' (aka 'int')
> > 'typeof_unqual(__ob_trap const int)' (aka '__ob_trap const int')
>
> So how can something be called a qualifier if unqual doesn't strip it?
>

Within Clang internals we call it a "type specifier" keyword with the
closest analogous thing being _BitInt. Even the attribute spelling of
OBTs boils down to a type specifier being applied to a base type.

This hasn't been clearly externalized in the documentation -- we can
work to improve that.

> (We might already have had this discussion, but I can't find the answer
> in the LLVM documentation page and didn't search our previous
> correspondence on this).
>

Justin

David Laight

unread,
Apr 2, 2026, 5:13:53 AM (8 days ago) Apr 2
to Kees Cook, Peter Zijlstra, Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov, Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor, kasa...@googlegroups.com, linu...@vger.kernel.org, ll...@lists.linux.dev, Linus Torvalds, Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton, linux-...@vger.kernel.org, linux-h...@vger.kernel.org, linux-...@vger.kernel.org
Adding all the required cases to the _Generic() doesn't scale.

typeof_unqual() needs to die.
Just using 'auto a = b;' should remove const and volatile - but gcc is buggy.
There are some alternatives that work in many cases.
(It has all been discussed before.)
In most cases you can use 'auto a = (b) + 0'.
That does do integer promotions - but they happen as soon as 'a' is
used; so it pretty much doesn't change the type of value, just the
type of the variable.

David

Reply all
Reply to author
Forward
0 new messages