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
