kees wrote:

> > This one, however, I think it not what we want, but I may be missing 
> > something.
> > ```
> > int __ob_trap src = bigger_than_255;
> > ...
> > char dest = src;
> > ```
> 
> I don't think that's correct, it's equivalent to saying
> 
> ```
> int64 __ob_trap src = bigger_than_2_to_32;
> ...
> int dest = src;
> ```
> 
> Should not trap, and similarly

Yes, this should not trap.

> 
> ```
> void f(int);
> int64 __ob_trap src = bigger_than_2_to_32;
> f(src);
> ```
> 
> Would also not trap.

Also correct, this should not trap.

> It also raises questions about what happens with
> 
> ```
> int __ob_wrap src = bigger_than_2_to_32;
> ...
> char dest = src;
> ```

`src` takes the wrapped value of `bigger_than_2_to_32` without complaint since 
its Overflow Behavior is to wrap. Then `dest` gets a potentially truncated 
value from `src` because `dest` does not specify any Overflow Behavior, so it 
falls back to the behavior in the standard: it is unsigned, so it wraps.

> If ob_trap is ignored, ob_wrap should similarly be ignored, and thus we have 
> UB overflow again.

I don't agree: the UB is related to using non-OBT variables. That is unchanged. 
(And to be really careful, it's actually not UB, but rather the larger set of 
"Overflow Behavior": unsigned overflow isn't UB.)

> > I don't think we want a trap on the `dest` assignment, since it isn't 
> > `__ob_trap`. It doesn't care about the truncation. This is a "sided" 
> > operation, unlike the arithmetic.
> 
> I disagree - the type has stated "overflow must have defined behavior', and 
> in this case that behavior is to trap. This change implicitly subsumes that 
> behavior, silencing the overflow trap, and rendering the overflow UB once 
> more.

For the OBT variable, overflows must follow a specific behavior on assignment: 
OBT indicates the behavior when *unable to represent a given value in the 
variable's storage* It cannot mean anything else; it's not a conceptual 
enforcement: it needs to be about managing the failure to represent a value in 
a given storage. The storage is exactly the variable itself, so only that 
variable can be involved.

Specifically, for roll out in Linux, we need to be able to migrate to new 
types, which means we can't have assignments to a non-OBT variable suddenly 
gain instrumentation.

For example, if a codebase has this:
```
int big = runtime_1024;
...
char byte = big;
```

If we make only `byte` an trapping OBT, there is no surprise: we're asking that 
`byte` be specifically instrumented to trap if the value to be assigned cannot 
be represented:

```
int big = runtime_1024;
...
char __ob_trap byte = big; // traps: "byte" would overflow
```

If we make only `big` an OBT, we cannot have `byte` trap because it is _not_ 
marked to care about overflow behavior.

```
int __ob_trap big = runtime_1024;
...
char byte = big; // must not trap: "big" did not overflow!
```

OBT needs to apply only to OBT annotated variable assignments, either explicit 
(`=`) or implicit (arithmetic intermediaries). The only place where we pollute 
this is during arithmetic operations where non-OBT gains OBT during implicit 
casting/promotion. The way OUT of that is the `__strict` (or `__strong 
typedef`) behavior where no implicit casts can involve an annotated variable.

If we don't follow what I'm describing, this becomes meaningless:

```
int __ob_trap big = runtime_1024;
...
char __ob_wrap byte = big; // is this supposed to wrap or trap? I say wrap -- 
we're describing how "byte" behaves
```

How can we perform an assignment where we _want_ a wrapping behavior if 
suddenly `ob_trap` dominates even from the RHS?

And this gets into the explicit cast stuff I mentioned:

```
int big = runtime_1024;
...
return (char __ob_trap)big;
```

This creates a `char __ob_trap` intermediate, and gets assigned the value of 
`big`, so it must trap. Explicit casts must behave as assignments for OBT. 
Without this, adding `__strong typedef` becomes impossible as there is no way 
to perform the overflow checking to get matching sizes for arithmetic:

```
__strong typedef u16 __ob_trap tu16;

int big;
u8 __ob_wrap small;
...
tu16 result = (tu16)big * (tu16)small;
```

This needs to catch any `big` value that cannot be represented by `u16` at cast 
time, otherwise we silently lose visibility into the overflow.

https://github.com/llvm/llvm-project/pull/148914
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to