[PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types

Kees Cook posted 5 patches 16 hours ago
[PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 16 hours ago
While Linux's use of -fno-strict-overflow means that all arithmetic
operations have a defined behavior (2's-complement wrapping), there
isn't a way to unambiguously specify if a given variable was designed
or intended to wrap around by the author.

Introduce explicit trapping and wrapping types for all bit widths
including architecture word length (i.e. "long"), signed and unsigned,
for use going forward for unambiguous arithmetic, now available via
Clang 23+'s Overflow Behavior Types[1] (CONFIG_OVERFLOW_BEHAVIOR_TYPES=y).

Bike shedding time! How should these be named? We already have the short
bit width types, named as: {u,s}{8,16,32,64}. We need to construct new
type names that also indicate their overflow behavior: "trapping" or
"wrapping". And we need to capture the "architectural word" length type
too (i.e. what "unsigned long" or "size_t" captures).

Whole word addition:
- Pro: Unambiguous
- Con: Long. E.g. suffixed "u16_trap", or prefixed "wrap_u16"

Single letter addition, "t" for "trap" and "w" for "wrap":
- At the end: but "u8t" looks like the "t" is "type", like "uint8_t".
- At the front: but "wu8" looks like the "w" is "wide", like "wchar_t".

Current straw-man proposal is single letter suffix because it vaguely
felt like the least bad of all choices, and they should be short or
everyone will just continue to type "int". :)

Link: https://clang.llvm.org/docs/OverflowBehaviorTypes.html [1]
Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: Justin Stitt <justinstitt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Finn Thain <fthain@linux-m68k.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: "Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
Cc: <llvm@lists.linux.dev>
---
 include/linux/types.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/include/linux/types.h b/include/linux/types.h
index 7e71d260763c..786eb2c9775f 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -94,6 +94,30 @@ typedef unsigned int		uint;
 typedef unsigned long		ulong;
 typedef unsigned long long	ullong;
 
+/* Trapping types. */
+typedef u8 __ob_trap		u8t;
+typedef u16 __ob_trap		u16t;
+typedef u32 __ob_trap		u32t;
+typedef u64 __ob_trap		u64t;
+typedef unsigned long __ob_trap	ulongt;
+typedef s8 __ob_trap		s8t;
+typedef s16 __ob_trap		s16t;
+typedef s32 __ob_trap		s32t;
+typedef s64 __ob_trap		s64t;
+typedef signed long __ob_trap	slongt;
+
+/* Wrapping types. */
+typedef u8 __ob_wrap		u8w;
+typedef u16 __ob_wrap		u16w;
+typedef u32 __ob_wrap		u32w;
+typedef u64 __ob_wrap		u64w;
+typedef unsigned long __ob_wrap	ulongw;
+typedef s8 __ob_wrap		s8w;
+typedef s16 __ob_wrap		s16w;
+typedef s32 __ob_wrap		s32w;
+typedef s64 __ob_wrap		s64w;
+typedef signed long __ob_wrap	slongw;
+
 #ifndef __BIT_TYPES_DEFINED__
 #define __BIT_TYPES_DEFINED__
 
-- 
2.34.1

Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 15 hours ago
On Tue, 31 Mar 2026 at 09:37, Kees Cook <kees@kernel.org> wrote:
>
> Current straw-man proposal is single letter suffix because it vaguely
> felt like the least bad of all choices, and they should be short or
> everyone will just continue to type "int". :)

Violently disagree.

I'd rather have people continue to use other types than have somethign
that isn't visually obvious for *VERY* subtle semantic changes.

If somebody starts using explicitly trapping types, they need to say
so. Not just *say* so, but scream it at the top of their lungs. No
hidden subtle behavior changes. This needs to look _very_different_.

No stupid one-character things. If we go down this path it would need
to be "wrapping_u32" or whatever.

That said, I think the trapping behavior is unacceptable unless
there's some way to recover from it. An dno, that "some way" is not
the broken C++ style exception handling. That thing is pure and utter
shit, and fragile as hell. Anything that requires trying to unwind the
stack is just a complete no-go because it's going to be buggy and
untestable (sure, you can have test-cases and the unwinding will work
for *those*, but...)

I don't actually see any sane interface. The "unsafe_get_user()" thing
with actual labels and exception tables works very well, but it would
require wrapping all trapping operations in a macro.

Which is maybe not a bad idea - it's almost certainly better than the
overflow builtins - but might also be disgusting. Hard to tell.

              Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 12 hours ago
On Tue, Mar 31, 2026 at 10:10:52AM -0700, Linus Torvalds wrote:
> On Tue, 31 Mar 2026 at 09:37, Kees Cook <kees@kernel.org> wrote:
> >
> > Current straw-man proposal is single letter suffix because it vaguely
> > felt like the least bad of all choices, and they should be short or
> > everyone will just continue to type "int". :)
> [...]
> If somebody starts using explicitly trapping types, they need to say
> so. Not just *say* so, but scream it at the top of their lungs. No
> hidden subtle behavior changes. This needs to look _very_different_.
> 
> No stupid one-character things. If we go down this path it would need
> to be "wrapping_u32" or whatever.

Yeah, that's fine. I'm fine calling these types whatever we want
(regardless of how we ultimately bolt exception handling to them).

The only reason I had this proposal using a short forms was to make
it "easy" to get counters/indexes/iterators with as few characters as
possible. It all comes back to my "favorite" security flaw where a u8
counter wrapped during post-increment in a while loop. Why was it "u8"?
No good reason besides "it was even less to type than 'int'" AFAICT. :P

> I don't actually see any sane interface. The "unsafe_get_user()" thing
> with actual labels and exception tables works very well, but it would
> require wrapping all trapping operations in a macro.

Mark Rutland had strong reservations about function-level annotations,
but I wonder if the combination of new type _and_ function-level
annotation could get us something near what would be palatable:


int __overflow_label(boom)
something(...)
{
	u8 __ob_trap count;
	...
	take_locks();
	...
	while (thing())
		count++;
	destroy_the_world_if_count_wraps(count);
	...
	return 0;

boom:
	unlock_and_clean_up(...);
	return -EINVAL;
}


This way not _all_ math is covered by the label, only the trapping math.

Or we could make the label a global part of the language itself so it
wouldn't need to be a function annotation, but rather a _required_
element of any function that uses a trapping type?

-Kees

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 12 hours ago
On Tue, 31 Mar 2026 at 13:03, Kees Cook <kees@kernel.org> wrote:
>
> Mark Rutland had strong reservations about function-level annotations,
> but I wonder if the combination of new type _and_ function-level
> annotation could get us something near what would be palatable:

Yes, if we had some way to specify the label, that actually looks
really nice to me.

So with _this_ kind of interface, all my reservations about it go away.

And as long as the compiler actually requires that label to exist when
trapping arithmetic is done, I don't think people will use it without
having fixups.

> Or we could make the label a global part of the language itself so it
> wouldn't need to be a function annotation, but rather a _required_
> element of any function that uses a trapping type?

Yes, I'd be ok with that too, because I think in practice you
typically only ever have one, and I guess you could use local labels -
or multiple functions - if you really needed to have different
targets.

We have a few years of experience with "unsafe_get_user()" and
friends, and a few hundred places that use it, and while it's common
to have several cases in one function, I can't think of a single case
where we actually had more than one error target.

I tried a quick grep, and nothing jumped out at me.

(And a lot of them use "Efault" or "efault" as the target name, so it
probably would have been fine with a default name)

            Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 12 hours ago
On Tue, Mar 31, 2026 at 01:11:22PM -0700, Linus Torvalds wrote:
> On Tue, 31 Mar 2026 at 13:03, Kees Cook <kees@kernel.org> wrote:
> >
> > Mark Rutland had strong reservations about function-level annotations,
> > but I wonder if the combination of new type _and_ function-level
> > annotation could get us something near what would be palatable:
> 
> Yes, if we had some way to specify the label, that actually looks
> really nice to me.
> 
> So with _this_ kind of interface, all my reservations about it go away.
> 
> And as long as the compiler actually requires that label to exist when
> trapping arithmetic is done, I don't think people will use it without
> having fixups.
> 
> > Or we could make the label a global part of the language itself so it
> > wouldn't need to be a function annotation, but rather a _required_
> > element of any function that uses a trapping type?
> 
> Yes, I'd be ok with that too, because I think in practice you
> typically only ever have one, and I guess you could use local labels -
> or multiple functions - if you really needed to have different
> targets.

Yeah, as you mentioned earlier, I'd agree that nesting is rarely
useful. The only thing I'd want to be careful about is ordering/scope. I
*think* it would just operate as a "goto" and things like the cleanup.h
handlers wouldn't be involved: they operate when a scope is crossed
like before. And I think the overflow result wouldn't be represented
anywhere. i.e. the wrapped/truncated value wouldn't be stored:

int func()
{
	...
	u8 __ob_trap product = 5;
	...
	product = a * b; // if store is truncated, goto __overflow
	...
	return product;

__overflow:
	pr_info("%u\n", product); // shows "5"
	return -1;
}

(Isn't this just an implicit "try"?)

-Kees

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Peter Zijlstra 2 minutes ago
On Tue, Mar 31, 2026 at 01:31:16PM -0700, Kees Cook wrote:

> int func()
> {
> 	...
> 	u8 __ob_trap product = 5;
> 	...
> 	product = a * b; // if store is truncated, goto __overflow
> 	...
> 	return product;
> 
> __overflow:
> 	pr_info("%u\n", product); // shows "5"

I'm confused by this 'product is still 5' thing. It seems to me that
making this happen will, in general, require more instructions/registers
than allowing the old value to be clobbered and have product be the
truncated result of whatever overflow.

Specifically, what is the value of preserving the old value?

> 	return -1;
> }
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Peter Zijlstra 28 minutes ago
On Tue, Mar 31, 2026 at 01:31:16PM -0700, Kees Cook wrote:

(still slowly digesting the thread)

> Yeah, as you mentioned earlier, I'd agree that nesting is rarely
> useful. The only thing I'd want to be careful about is ordering/scope. I
> *think* it would just operate as a "goto" and things like the cleanup.h
> handlers wouldn't be involved: they operate when a scope is crossed
> like before. And I think the overflow result wouldn't be represented
> anywhere. i.e. the wrapped/truncated value wouldn't be stored:
> 
> int func()
> {
> 	...
> 	u8 __ob_trap product = 5;
> 	...
> 	product = a * b; // if store is truncated, goto __overflow
> 	...
> 	return product;
> 
> __overflow:
> 	pr_info("%u\n", product); // shows "5"
> 	return -1;
> }

Note that there is a 'fun' problem with this in combination with
cleanup.h.

Something like:

int func()
{
	u8 __ob_trap prod = 0;

	scoped_guard (mutex, &my_lock) {
		prod = a * b;
	}

	return prod;

__overflow:
	// whatever
	return -1;
}

is fine. *HOWEVER*, something like:

int func()
{
	int __ob_trap size = base + count * extra;
	int err;

	struct my_obj *obj __cleanup(kfree) = kzalloc(size, GFP_KERNEL);

	err = my_obj_init(obj);
	if (err)
		return ERR_PTR(err);

	return_ptr(obj);

__overflow:
	// what now..
	return NULL;
}

is most terribly broken. Specifically, the goto will jump into the scope
of obj -- and that is not allowed.
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 12 hours ago
On Tue, 31 Mar 2026 at 13:31, Kees Cook <kees@kernel.org> wrote:
>
> (Isn't this just an implicit "try"?)

Yes. And I think that's ok.

I think try/catch is broken for a few reasons, but the fact that catch
and try are tied together so closely is the main one. You can't "try"
inside a scope without having the "catch" inside the same scope.

So then the solution is to just move the try to the outermost layer,
and I think that's pretty much what everybody does.

But at that point, why not just move it *all* the way out, and make it
implicit and invisible?

Which is kind of exactly what your suggestion is all about, and that's
why I like it so much.

It *literally* fixes try/catch. It makes the only really valid usage
model just work better.

(There are other reasons I dislike try/catch too, the whole
"exceptions across function boundaries" being another one that your
model avoids).

                Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Justin Stitt 11 hours ago
Hi,

On Tue, Mar 31, 2026 at 2:05 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> On Tue, 31 Mar 2026 at 13:31, Kees Cook <kees@kernel.org> wrote:
> >
> > (Isn't this just an implicit "try"?)
>
> Yes. And I think that's ok.
>
> I think try/catch is broken for a few reasons, but the fact that catch
> and try are tied together so closely is the main one. You can't "try"
> inside a scope without having the "catch" inside the same scope.
>
> So then the solution is to just move the try to the outermost layer,
> and I think that's pretty much what everybody does.
>
> But at that point, why not just move it *all* the way out, and make it
> implicit and invisible?

How do we feel about type-defined labels? We can specify sane default
handlers where we define the types:

        typedef int __attribute__((overflow_behavior(trap, __handle_me)));

... and define specialized handlers later on

int func()
{
        ...
        u8 __attribute__((overflow_behavior(trap, __BOOOOM))) product = 5;
        ...
        product = a * b; // if store is truncated, goto __overflow
        ...
        return product;

__BOOOOM:
        pr_info("%u\n", product); // shows "5"
        return -1;
}

We would then probably want a kernel shorthand to avoid long type definitions.

        #define __TRAP(handler) __attribute__((overflow_behavior(trap,
handler)))


At least this way the label is always defined somewhere in-source
rather than by a magic -fhandle-my-overflow-at=__overflow


>
> Which is kind of exactly what your suggestion is all about, and that's
> why I like it so much.
>
> It *literally* fixes try/catch. It makes the only really valid usage
> model just work better.
>
> (There are other reasons I dislike try/catch too, the whole
> "exceptions across function boundaries" being another one that your
> model avoids).
>
>                 Linus

Justin
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 9 hours ago
On Tue, 31 Mar 2026 at 14:50, Justin Stitt <justinstitt@google.com> wrote:
>
> How do we feel about type-defined labels? We can specify sane default
> handlers where we define the types:
>
>         typedef int __attribute__((overflow_behavior(trap, __handle_me)));
>
> ... and define specialized handlers later on

That sounds like an interesting interface, but I think it ends up
being kind of odd, because normally the type definition would be in
some global scope, while the 'handler' would be a local label name.

I think that in some situations - and certainly other projects - it
would make a lot of sense to have the trap handler be a global
function in that situation (ie "abort"), but with that being
explicitly *not* what the kernel would want, it seems a bit odd to
specify the name of a label that then is used in a totally different
context.

So in your example:

> int func()
> {
>         ...
>         u8 __attribute__((overflow_behavior(trap, __BOOOOM))) product = 5;
>         ...
>         product = a * b; // if store is truncated, goto __overflow
>         ...
>         return product;
>
> __BOOOOM:
>         pr_info("%u\n", product); // shows "5"
>         return -1;
> }

The above makes total sense, but imagine instead the code being
something more like this:

Some header file does this:

  typedef unsigned int __attribute__((overflow_behavior(trap,
__BOOOOM))) u32_overflow_t;

  struct some_random_struct {
        u32_overflow_t usage_count;
        ...
  };

The implementation for looking up those structs then looks something like this:

  struct some_random_struct *get_entry(int hashval)
  {
        struct some_random_struct *n;
        spin_lock(&hashlock);
        n = find_entry(hashval);
        if (n)
                n->usage_count++;
        spin_unlock(&hashlock);
        return n;

  __BOOOOM:
        WARN_ON_ONCE("Entry 'n' overflowed\n", n->name);
        spin_unlock(&hashlock);
        return NULL;
   }

does that still make sense?

Now, I'm not *opposed* to this kind of interface - we'd presumably
just use something like "overflow" for the label name anyway - and it
allows people to use whatever label names make sense for a project so
it's clearly a nice feature.

It just feels a bit odd. But maybe it makes perfect sense at a
compiler level as a "it's just declaring the token to be used for the
exception label".

                Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 9 hours ago
On Tue, Mar 31, 2026 at 02:50:39PM -0700, Justin Stitt wrote:
> On Tue, Mar 31, 2026 at 2:05 PM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > On Tue, 31 Mar 2026 at 13:31, Kees Cook <kees@kernel.org> wrote:
> > >
> > > (Isn't this just an implicit "try"?)
> >
> > Yes. And I think that's ok.
> >
> > I think try/catch is broken for a few reasons, but the fact that catch
> > and try are tied together so closely is the main one. You can't "try"
> > inside a scope without having the "catch" inside the same scope.
> >
> > So then the solution is to just move the try to the outermost layer,
> > and I think that's pretty much what everybody does.
> >
> > But at that point, why not just move it *all* the way out, and make it
> > implicit and invisible?
> 
> How do we feel about type-defined labels? We can specify sane default
> handlers where we define the types:
> 
>    typedef int __attribute__((overflow_behavior(trap, __handle_me))) trapping_int;
> 
> ... and define specialized handlers later on
> 
> int func()
> {
>         ...
>         u8 __attribute__((overflow_behavior(trap, __BOOOOM))) product = 5;
>         ...
>         product = a * b; // if store is truncated, goto __overflow
>         ...
>         return product;
> 
> __BOOOOM:
>         pr_info("%u\n", product); // shows "5"
>         return -1;
> }

Yeah, I think this could work. As long as there's nothing special about
the label mapping (i.e. many types can share the same label).

> We would then probably want a kernel shorthand to avoid long type definitions.
> 
>         #define __TRAP(handler) __attribute__((overflow_behavior(trap,
> handler)))
> 
> 
> At least this way the label is always defined somewhere in-source
> rather than by a magic -fhandle-my-overflow-at=__overflow

Yeah, this sticks to Peter's "define in source" mandate from Plumbers.

Linus, does that still sound reasonable?

Also, is the preference still for "loud" names ("trap_u32") for the
trapping scalar typedefs, or does the advent of the "required label on
usage" make it more reasonable to have shorter names ("u32t")? I'm fine
either way. I think there are pros and cons all over the place for the
naming.

-Kees

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 12 hours ago
On Tue, 31 Mar 2026 at 13:11, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> We have a few years of experience with "unsafe_get_user()" and
> friends, and a few hundred places that use it, and while it's common
> to have several cases in one function, I can't think of a single case
> where we actually had more than one error target.
>
> I tried a quick grep, and nothing jumped out at me.

And the *moment* I sent that reply, I went "Wait a minute", and looked
at strncpy_from_user().

So we do actually have at least one case of multiple exception labels:
the first one in that function handles the "potentially unaligned word
access causes page fault, fall back to byte-at-a-time" while the
second one is final and fatal and results in -EFAULT.

But that case could have been written with the byte-at-a-time case as
a separate inline function, so it would all have worked fine even
without explicitly named exception entries.

In some situations, the explicit names may be very useful just to
document things: in that case the 'byte_at_a_time" label does do that,
but I don't think it's a very big issue.

And it's likely even less of an issue for arithmetic overflows than it
is for user space accesses.

So yeah, with better compiler support, I think that whole trapping
behavior would be great.

               Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Miguel Ojeda 15 hours ago
On Tue, Mar 31, 2026 at 7:11 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> No stupid one-character things. If we go down this path it would need
> to be "wrapping_u32" or whatever.

That sounds close to similar types provided by Rust, i.e. if something
like these types are used, then it would be nice to match names if
possible (assuming they are similar enough, i.e. no surprises).

e.g. with generics they do `Wrapping<u32>` or, in other cases, without
generics they name them something like e.g. `NonZeroU32`.

Having said that...

> This needs to look _very_different_.

I think there is an actual risk of someone e.g. copying an expression
from one place to another, with the operators behaving differently,
yeah.

In the Rust side, even if those "explicit" types like the
`wrapping_u32` you suggest exist, we generally use the methods on the
normal integers instead, e.g.

    i.wrapping_add(1)

    micros.saturating_mul(NSEC_PER_USEC)

    self.index.checked_mul(page::PAGE_SIZE)?

etc.

The advantage is precisely that it is more explicit and avoids
confusing the operators when copy-pasting code and so on.

So that could perhaps be an option? Kees et al. have been thinking
about this for a long time as far as I recall.

[ And for the usual operators on integer primitives, we panic by
default (configurable via Kconfig), but at least that applies to all
Rust code, which is all new, and kernel developers get accustomed to
think about what they actually want for a particular operation and
whether they need one of the explicit behaviors above, so it has been
good so far, but it remains to be seen what happens when we have way
more code around etc. It does mean someone copying a simple math
expression from C to Rust could forget about it, though... ]

Cheers,
Miguel
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 14 hours ago
On Tue, Mar 31, 2026 at 07:47:44PM +0200, Miguel Ojeda wrote:
> In the Rust side, even if those "explicit" types like the
> `wrapping_u32` you suggest exist, we generally use the methods on the
> normal integers instead, e.g.
> 
>     i.wrapping_add(1)
> 
>     micros.saturating_mul(NSEC_PER_USEC)
> 
>     self.index.checked_mul(page::PAGE_SIZE)?
> 
> etc.
> 
> The advantage is precisely that it is more explicit and avoids
> confusing the operators when copy-pasting code and so on.
> 
> So that could perhaps be an option? Kees et al. have been thinking
> about this for a long time as far as I recall.

I went through 7 revisions of creating helpers/accessors[1] (and
function-level annotations) and it ultimately went unused. From memory,
this was specifically from Jakub Kicinski (found breaking up readable
math statements into a series of helpers too bulky), Peter Zijlstra and
Mark Rutland (wanted strictly type-based system)[2].

Link: https://lore.kernel.org/lkml/?q=%22overflow%3A+Introduce+wrapping+helpers%22 [1]
Link: https://lore.kernel.org/lkml/20240424191740.3088894-4-keescook@chromium.org/ [2]

I view accessors as a non-starter given the near universal pushback
against them in C.

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 14 hours ago
On Tue, 31 Mar 2026 at 10:48, Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> In the Rust side, even if those "explicit" types like the
> `wrapping_u32` you suggest exist, we generally use the methods on the
> normal integers instead, e.g.

In that case the types in question should always be very much opaque,
and not usable as-is by existing compilers that don't have attributes.

My feeling is that that will discourage use enormously for when people
want to just say "yes, I know this wraps, and it's ok".

That said, for the *trapping* types, I do think that we likely need an
opaque type, because I really feel like using

   trapping_u32 x;
   ...
   x++;

is a complete and utter mis-design. It makes the "x++' have random behavior that

 (a) cannot be recovered from (maybe we're holding random locks)

 (b) is completely invisible in the context of the code, because the
type may be somewhere very different

and I think both of those are fundamental design mistakes.

And no, "dead machine" is *still* not an acceptable form of "that's
not random behavior".

So I think wrapping and trapping are fundamentally very different. The
words may look the same. The semantics may often be discussed
together. But one is explicitly marking something as "overflow is safe
and expected", and that's the actual real SAFE case.

The other is saying "overflow needs special handling". And the key
here is that we need to have some way to *state* what said special
handling is, and we need to do it at the point where that special
handling is needed. Not some generic exception handler that has to
figure things out from some unknown context.

Very very different things, and they need very very different
interfaces and very very different infrastructure.

Anything that says "these are two faces of the same coin and are just
different attributes on the type" is simply broken by design.

                 Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 14 hours ago
On Tue, Mar 31, 2026 at 11:02:03AM -0700, Linus Torvalds wrote:
> On Tue, 31 Mar 2026 at 10:48, Miguel Ojeda
> <miguel.ojeda.sandonis@gmail.com> wrote:
> >
> > In the Rust side, even if those "explicit" types like the
> > `wrapping_u32` you suggest exist, we generally use the methods on the
> > normal integers instead, e.g.
> 
> In that case the types in question should always be very much opaque,
> and not usable as-is by existing compilers that don't have attributes.
> 
> My feeling is that that will discourage use enormously for when people
> want to just say "yes, I know this wraps, and it's ok".
> 
> That said, for the *trapping* types, I do think that we likely need an
> opaque type, because I really feel like using
> 
>    trapping_u32 x;
>    ...
>    x++;
> 
> is a complete and utter mis-design. It makes the "x++' have random behavior that
> 
>  (a) cannot be recovered from (maybe we're holding random locks)
> 
>  (b) is completely invisible in the context of the code, because the
> type may be somewhere very different
> 
> and I think both of those are fundamental design mistakes.

This design is specifically what Peter was requesting, and what actually
integrates with C. I agree with you that the core problem is "cannot be
recovered from", but that misses the point of these types. The point is
that all of their uses are _supposed_ to have been written in a way that
no overflow is possible (just like all the other types). But this is
the problem: bugs keep happening, no matter what people try to do. And
in fact, to support these kinds of in-code overflow checking, there are
even idiom exclusions for these types (based on what you pointed out in
the original RFC) to allow for things like:

	if (var + offset < var) { ... }

If the code was written perfectly, then there's no problem. If there was
a bug that allows for overflow then you get a crash instead of totally
insane behavior that is almost always exploitable in a way that the
system gets compromised. That is a net benefit, even if crashes are
still bad.

The point is to make a type that still works with C and all the associated
APIs (e.g. format strings, native arithmetic, etc) without creating the
mess that Jakub, Peter, and others (correctly) balked at around accessors
for doing function based math.

> So I think wrapping and trapping are fundamentally very different. The
> words may look the same. The semantics may often be discussed
> together. But one is explicitly marking something as "overflow is safe
> and expected", and that's the actual real SAFE case.

Right. Mixing the term "safe" between these is certainly a mistake in
the documentation. We can fix all of that.

> The other is saying "overflow needs special handling". And the key
> here is that we need to have some way to *state* what said special
> handling is, and we need to do it at the point where that special
> handling is needed. Not some generic exception handler that has to
> figure things out from some unknown context.

The generic exception handler, right now, is the distant back-stop to
catch exceptional cases that nothing else was written to catch. Like
uncorrectable RAM errors. Using a trapping type isn't there for people
to _intend_ to crash the system. :)

But, yes, I agree that having a way to require in-place overflow
management would be the perfect solution, but no one seems to be able to
agree on it. The trouble with C arithmetic is that the overflow state is
"hidden". It's like the remainder from division: math statements need an
overflow case built in, almost like a ?:, but from a syntax perspective,
there's not been anything that stuck. The state of the art in C is
"make sure you test for overflow manually first", and these types allow
for that.

-Kees

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 14 hours ago
On Tue, 31 Mar 2026 at 11:32, Kees Cook <kees@kernel.org> wrote:
>
> If the code was written perfectly, then there's no problem.

My point is that BUG_ON() DOES NTO SOLVE THE PROBLEM.

> The point is to make a type that still works with C and all the associated
> APIs (e.g. format strings, native arithmetic, etc) without creating the
> mess that Jakub, Peter, and others (correctly) balked at around accessors
> for doing function based math.

Has anybody tried to suggest that "use a label" model?

Because I 100% agree that the current overflow handling is pure
garbage, and doesn't allow the code to be used in any kind of sane
code.

But I think that's solvable with the "branch out on error to be
handled elsewhere" model.

               Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 14 hours ago
On Tue, 31 Mar 2026 at 11:02, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> The other is saying "overflow needs special handling"

Btw, this is why I also completely despise the current overflow builtins.

Yes, they handle overflow. But they don't treat it as some *special*
thing. They are garbage that forces code that uses them to be garbage.

If you want to use the overflow builtins (or our wrappers aorund
them), you can't just do the math. You have to do crazy crap like

     int end;
     if (check_add_overflow(start, len, &end))
        ... handle overflow ...
     do_something(start, end);

which obviously no sane person will do, when they can just write

   do_something(start, start+len);

instead (particularly since usually that "start+len" is just a tiny
detail in the code anyway).

Notice how it breaks up the code logic, and also requires you to add
random intermediate variables etc. It's bad, it makes the code look
bad, and people don't use it as a result.

The reason people like exception handling is that you can make the
fixup be done elsewhere, and you *don't* have to deal with it at the
point where you just want to use the result and with silly
intermediate variables etc.

IOW, exception handling means that you can continue to use the normal
flow of code for the normal case, and you deal with errors separately.

That is good. Much better than the "check_sub_overflow()" kind of crazy thing.

So I very much understand why all modern languages do it - but at the
same time most exception handling is complete garbage, because almost
everybody ends up thinking that it should nest syntactically, which is
completely wrong.

Error handling does not nest: it exits. If you have two different
exceptional cases in the same expression or statement, they have no
inherent nesting, and the order isn't even someting you should care
about. But they can cause different error codes or different fixups,
and they need *separate* handling.

This is why the kernel user space exception handling ended up with a
"label" model the moment the compilers could deal with it (in fact, I
very much asked for that interface, and compilers finally gave it to
me after years).

It means that you can move the exception handling out of line, without
having to interrupt the actual normal code flow. And youc an do it
without the bogus nesting that makes no sense.

So I think overflow handling should do the same. Instead of the bad
"check_sub_overflow()" model we have now, we should have

     res = add_overflow(a,b,label);

and now you can use a trapping operation *without* having to break the
normal flow of code, ie you can do

      do_something(start, add_overflow(start, len, overflow))
      ...
  overflow:
      // Maybe needs to release locks, who knows
      return -EINVAL;

notice?

Wrapping does not need this kind of thing. Wrapping is literally a "I
know I don't need to care", while trapping is a "I know I need to
handle it".

It's just that handling the trapping should not need to be done right
where the operation is done.

And in C, that means "goto". And I actualyl will claim that "goto" is
superior to most crazy language models with some "try()" block that
nests.

Language designers have been corrupted by "things must nest". BS.

             Linus
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Kees Cook 14 hours ago
On Tue, Mar 31, 2026 at 11:25:20AM -0700, Linus Torvalds wrote:
> If you want to use the overflow builtins (or our wrappers aorund
> them), you can't just do the math. You have to do crazy crap like
> 
>      int end;
>      if (check_add_overflow(start, len, &end))
>         ... handle overflow ...
>      do_something(start, end);
> 
> which obviously no sane person will do, when they can just write
> 
>    do_something(start, start+len);
> [...]
> So I think overflow handling should do the same. Instead of the bad
> "check_sub_overflow()" model we have now, we should have
> 
>      res = add_overflow(a,b,label);
> 
> and now you can use a trapping operation *without* having to break the
> normal flow of code, ie you can do
> 
>       do_something(start, add_overflow(start, len, overflow))
>       ...
>   overflow:
>       // Maybe needs to release locks, who knows
>       return -EINVAL;
> 
> notice?

The syntax problem (as made clear by many other people, and even you
here in the first half of this email) is that no one will use function
based math primitives. Everyone absolutely hates it. I would have gone
this route (as it is the design of the user-access code), but everyone
so violently rejected functional math that it seemed not even worth the
attempt.

> Wrapping does not need this kind of thing. Wrapping is literally a "I
> know I don't need to care", while trapping is a "I know I need to
> handle it".
> 
> It's just that handling the trapping should not need to be done right
> where the operation is done.

I agree completely. The trouble is how to build that into the existing
arithmetic statement syntax of C. This has been an unsolved problem for
50 years. :(

-- 
Kees Cook
Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
Posted by Linus Torvalds 12 hours ago
On Tue, 31 Mar 2026 at 11:59, Kees Cook <kees@kernel.org> wrote:
>
> The syntax problem (as made clear by many other people, and even you
> here in the first half of this email) is that no one will use function
> based math primitives.

I don't think that's true.

It's just that they have to be made simple enough to use, and have a
good *reason* to use them without the end result becoming horrendous.

Ok, so I just spent fifteen minutes trying it out, trying to aim for a
really simple syntax.

Look at this contrieved example where there are two different overflow
things with two different exception handlers. I decided to add a
"default" label that is just called "overflow", so you can write code
like this:

        static int testme(int a, int b, int c, int d)
        {
                return addo(addmulo(a,b,c,addmul_overflow),d);
        overflow:
                return -1;
        addmul_overflow:
                return -2;
        }

which obviously isn't pretty, but it's still at least somewhat
readable. It does a "addmul" and an "add", both with overflow
handling, and returns the end result.

If the final add overflows (which doesn't have an explicit overflow
label name), it goes to the default "overflow:" label.

And if the addmul overflows, it goes to addmul_overflow. It's all kind
of obvous, and not syntactically all that onerous.

And it does work:

        #define TEST(x) printf(#x "=%d\n", x)

        #define MAX_INT 2147483647

        int main(int argc, char **argv)
        {
                TEST(testme(1,2,3,4));
                TEST(testme(MAX_INT,2,3,4));
                TEST(testme(1,2,3,MAX_INT));
                return 0;
        }

results in:

        $ gcc -O2 ov.c && ./a.out
        testme(1,2,3,4)=11
        testme(MAX_INT,2,3,4)=-2
        testme(1,2,3,MAX_INT)=-1

and in this case gcc actually did everything at compile-time, so code
generation is actually good too: the compiler will optimize this to
hell and back.

But even *without* constant arguments, the compiler can actually
generate good code too:

                .globl  testme
                .type   testme, @function
        testme:
        .LFB11:
                .cfi_startproc
                imull   %edx, %esi
                jo      .L6
                addl    %edi, %esi
                jo      .L6
                addl    %ecx, %esi
                jo      .L15
                movl    %esi, %eax
                ret
        .L6:
                movl    $-2, %eax
                ret
        .L15:
                movl    $-1, %eax
                ret

that really isn't bad.

So the code is legible, the code generation is fine, and it's pretty
flexible. And are the macros complicated? No. This is literally the
code that did all this:

        #define __default_exception(a,b,...) b
        #define default_exception(...)
__default_exception(,##__VA_ARGS__,overflow)
        #define overflow_op(op,a,b,c) __builtin_##op##_overflow(a,b,c)

        #define __overflow(op,a,b,...) ({                       \
                __typeof__(a) __res;                            \
                if (overflow_op(op,a,b,&__res))                 \
                        goto default_exception(__VA_ARGS__);    \
                __res; })

        #define addo(a,b,...) __overflow(add,a,b,##__VA_ARGS__)
        #define mulo(a,b,...) __overflow(mul,a,b,##__VA_ARGS__)
        #define addmulo(a,b,c,...) addo(a,mulo(b,c,##__VA_ARGS__),##__VA_ARGS__)

Now will people ENJOY using "addo()" and things like that? No. Clearly
it's still *easier* and even clearer to just write

        return a + b*c + d;

and yes, that is more legible.

But no, I really *really* don't want people to be able to just
randomly say "I'm just going to kill the kernel if this overflows".

                 Linus