Can we just have struct inheritence already?

Timon Gehr timon.gehr at gmx.ch
Fri Jun 14 01:18:04 UTC 2019


On 14.06.19 02:41, Exil wrote:
> On Thursday, 13 June 2019 at 21:18:16 UTC, Timon Gehr wrote:
>> On 13.06.19 22:55, Exil wrote:
>>> On Thursday, 13 June 2019 at 19:21:53 UTC, Tim wrote:
>>>> On Tuesday, 11 June 2019 at 00:30:27 UTC, Walter Bright wrote:
>>>>> If you want @safe to mean "no undefined behavior", that is a valid 
>>>>> opinion, but that is not what @safe in D is currently defined as. 
>>>>> It is currently defined as "memory safe". If you can find a case 
>>>>> where an int with garbage in it can cause memory corruption in 
>>>>> @safe code, that would indeed be a bug in D.
>>>>
>>>> The following code causes memory corruption, because a bool has 
>>>> garbage in it.
>>>>
>>>> import std.stdio;
>>>>
>>>> // Returns newly allocated data with increased value if b is true.
>>>> // Returns same data otherwise.
>>>> const(int)* test(immutable int *data, bool b) @trusted
>>>> {
>>>>     int *data2;
>>>>     if(!b)
>>>>     {
>>>>         writeln("b seems to be false");
>>>>         // The cast can be trusted, because data2 will only be 
>>>> modified if b is true.
>>>>         data2 = cast(int*)data;
>>>>     }
>>>>     else
>>>>     {
>>>>         writeln("b seems to be true");
>>>>         data2 = new int(*data);
>>>>     }
>>>>
>>>>     if(b)
>>>>     {
>>>>         writeln("b seems to be true");
>>>>         *data2 += 1;
>>>>     }
>>>>     return data2;
>>>> }
>>>>
>>>> void main() @safe
>>>> {
>>>>     bool b = void;
>>>>     immutable int *data = new immutable int(1);
>>>>     writeln("data before: ", *data);
>>>>     const int *data2 = test(data, b);
>>>>     writeln("data after: ", *data);
>>>>     writeln("data2 after: ", *data2);
>>>> }
>>>>
>>>> After compiling it with dmd and running it I get the following output:
>>>> data before: 1
>>>> b seems to be false
>>>> b seems to be true
>>>> data after: 2
>>>> data2 after: 2
>>>>
>>>> The immutable integer pointed to by data is modified. The function 
>>>> test is @trusted, but only modifies the immutable data, because b 
>>>> seems to be true and false at the same time.
>>>> Normally a bool is internally 0 or 1 and the compiler can assume 
>>>> that. If b has another value and !b is implemented as ~b, then b and 
>>>> !b can both be true.
>>>>
>>>> This means, that uninitialized data can result in memory corruption.
>>>
>>> This problem happens because you are used @trusted. If you used @safe 
>>> you wouldn't be able to increment pointers and modify the values the 
>>> way you did in @trusted.
>>
>> What that code illustrates is that `void` initialization leads to 
>> boolean values that are both `true` and `false` at the same time.
>> The @trusted function in the example can't do anything bad assuming 
>> that `b` is either true or false. If `void` initialization is @safe, 
>> @trusted functions can no longer assume that boolean parameters cannot 
>> be `true` and `false` at the same time. What's more, neither can @safe 
>> functions.
>>
>> In my book, an optimizer that can't elide the `if(b)` in the above 
>> code is a bad optimizer. Therefore either `void` initialization should 
>> not be @safe, or `void` initialization of a bool should be guaranteed 
>> to result in a value that is either true or false, but not both.
> 
> They aren't both true and false at the same time. Merely the code that 
> is generated seems to be most likely checking that it is 1.

No. Tim explained _exactly_ what is going on. Please read before responding.

> This is more a bug with the compiler, nothing more.

It seems perfectly plausible that `void` initialization destroys 
invariants of types other than booleans, and that this destruction of 
invariants will lead to similar memory corruption problems.

Changing the compiler such that booleans do not have an invariant only 
fixes this instance of the problem, it does not address the general 
problem with `void` initialization in @safe code that it is a symptom of.

> It should only be checking if the 
> value is zero, anything else should be true.

That's precisely what it is doing, but it uses bitwise negation to flip 
the value of the bool. So both b and !b are not equal to zero.


More information about the Digitalmars-d mailing list