@safe accessing of union members

Paul Backus snarwin at gmail.com
Wed Mar 17 18:01:43 UTC 2021


On Wednesday, 17 March 2021 at 16:43:25 UTC, Q. Schroll wrote:
> There was a discussion lately about overlapping pointers in 
> unions, @safe and SumType.
>
> Obvious results: It is @safe overlapping some types with others 
> and accessing them in @safe code and it is un- at safe to do so 
> with other types.
>
> I had an insight that I wanted to share: invariants. A type has 
> invariants if there could be bit-patterns that are invalid.

Yes. This is exactly what the "Background" section of the DIP 
1035 [1] was trying to say.

> Breaking invariants incurs undefined behavior

Not necessarily. The statement

     int* p = cast(int*) 0xDEADBEEF;

...does not have undefined behavior. You only get undefined 
behavior if you actually dereference `p`.

In more general terms: undefined behavior doesn't come from the 
values themselves, but from specific *operations* on those 
values. The purpose of an invariant is to specify what conditions 
are necessary to ensure defined behavior for a given operation.

> So, what kinds of union uses are @safe?
> Answer: If all members of the union have no invariants.

This is overly narrow. Unions themselves have no invariants, even 
when their members do, because access to those members is 
forbidden in @safe code, and there is no operation you can 
perform on a union instance *as a whole* in @safe code whose 
behavior is potentially undefined.

Some examples of things you can do with a union that are always 
@safe, regardless of its members:

     union U { int* ptr; int num; }

     // Initialization is always @safe
     U a = { num: 123 };
     U b = { ptr: new int };
     // Copying is always @safe
     U c = b;
     // Bitwise comparison is always @safe
     assert(c is b);
     // Casting memory to const(ubyte) is always @safe
     writefln("Raw bytes: %(%02X %)", 
*cast(const(ubyte)[U.sizeof]*) &c);

> When should the language (conservatively) assume an aggregate 
> type (struct, class, etc.) has invariants?

The rules in the language spec [2] are mostly correct in this 
regard, though they leave out `bool` (and enum types, though 
that's a more debatable issue).

[1] 
https://github.com/dlang/DIPs/blob/c39f6ac62210e0604dcee99b0092c1930839f93a/DIPs/DIP1035.md#background
[2] https://dlang.org/spec/function.html#safe-values


More information about the Digitalmars-d mailing list