[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

Justin Stitt via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 24 18:07:36 PDT 2024


JustinStitt wrote:

> > > If you declare a variable as both wrapping and non-wrapping, is it wrapping?
> > 
> > 
> > I am not sure how to do this. I am sure that with the magic of C anything is possible but I can't conceive a way to have a variable both have the attribute and not have the attribute (to be clear, there doesn't exist a `__attribute__((no-wraps))` currently)
> 
> Say you declare a global variable like the following:
> 
> ```
> typedef int wrapint __attribute((wraps));
> extern wrapint x;
> int x = 0;
> ```
> 
> Is "x" wrapping?

No. But I am confused, isn't this just shadowing a global variable with a lesser-scoped one. Are they the same? What behavior do we want here?

> 
> > > If you mark a `short` wrapping, is the type after promotion wrapping?
> > 
> > 
> > This concerns the `-fsanitize=implicit-signed-integer-truncation` sanitizer which the wraps attribute disables. So the type boundaries pre- and post-promotion are not enforced by this sanitizer for wrapping types.
> 
> There are cases that don't involve truncation:
> 
> ```
> typedef short wrapshort __attribute((wraps));
> wrapshort x = 0x7FFF;
> int y = x*x*x*x;
> ```

Arithmetic cannot be performed on less-than-ints so the implicit promotions are put in place which lose the attribute. I just worked on an update to carry the wraps attribute through implicit integer promotion. 

However, after making the patch and testing it I am not sure what we want. Do we want to cancel implicit promotions for less-than-ints that possess the wraps attribute (doesn't sound spec compliant)? Or, should wrapping things still undergo promotion but now wrap at different bounds than what their original type specified?

If I make a wrapping char [-128, 127] and do some arithmetic on it it will be promoted to int (and still have the wraps attribute, with my patch) then proceed.

In the example below, `x*x*x*x*x` is `33,038,369,407` which is greater than INT_MAX `2,147,483,647` and will thus overflow (a few times). However, this overflow is happening at the integer boundaries not at the char boundaries.

```c
wrapchar x = 127;
int y = x*x*x*x*x; // result: -1321368961
```

The options are:
1) don't carry the wraps attribute through implicit promotions
2) carry the wraps attribute but use promoted-to-type's boundaries for wrapping
3) carry attribute and use the pre-promotion type's boundaries

More on this, I don't see how changing implementation from attribute-based to type-based resolves any of these design decisions. Neither approach is necessarily easier to implement or to understand for developers, if the right decisions are made in terms of behavior then the attribute approach can be just as useful and predictable.

https://github.com/llvm/llvm-project/pull/86618


More information about the cfe-commits mailing list