Jump to page: 1 2
Thread overview
bool passed by ref, safe or not ?
Jun 04
Basile B.
Jun 04
rkompass
Jun 05
Basile B.
Jun 05
Kagamin
Jun 05
Basile B.
Jun 05
Dukc
June 04

question in the header, code in the body, execute on a X86 or X86_64 CPU

module test;

void setIt(ref bool b) @safe
{
    b = false;
}

void main(string[] args)
{
    ushort a = 0b1111111111111111;
    bool* b = cast(bool*)&a;
    setIt(*b);
    assert(a == 0b1111111100000000); // what actually happens
    assert(a == 0b1111111111111110); // what would be safe
}

I understand that the notion of bool doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption.

Do I corrupt memory here or not ?
Is that a safety violation ?

June 04

On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:

>

question in the header, code in the body, execute on a X86 or X86_64 CPU

module test;

void setIt(ref bool b) @safe
{
    b = false;
}

void main(string[] args)
{
    ushort a = 0b1111111111111111;
    bool* b = cast(bool*)&a;
    setIt(*b);
    assert(a == 0b1111111100000000); // what actually happens
    assert(a == 0b1111111111111110); // what would be safe
}

I understand that the notion of bool doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption.

Do I corrupt memory here or not ?
Is that a safety violation ?

No everything is fine.
The bool is the same size like byte or char.
So your cast makes &a pointer to a byte.
And this byte has to be made completely zero by setIt, otherwise it would not be false in the sense of bool type.

June 05

On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:

>

question in the header, code in the body, execute on a X86 or X86_64 CPU

module test;

void setIt(ref bool b) @safe
{
    b = false;
}

void main(string[] args)
{
    ushort a = 0b1111111111111111;
    bool* b = cast(bool*)&a;
    setIt(*b);
    assert(a == 0b1111111100000000); // what actually happens
    assert(a == 0b1111111111111110); // what would be safe
}

I understand that the notion of bool doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption.

Do I corrupt memory here or not ?

I don't think so. You passed an address to a bool, which uses 8 bits of space, even though the compiler treats it as a 1-bit integer.

In order for your code to do what you expect, all bool writes would have to be read/modify/write operations. I don't think anyone would prefer this.

>

Is that a safety violation ?

No, you are not writing to memory you don't have access to. An address is pointing at a byte level, not a bit level.

-Steve

June 05

On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:

>
void main(string[] args)
{
    ushort a = 0b1111111111111111;
    bool* b = cast(bool*)&a;
    setIt(*b);
    assert(a == 0b1111111100000000); // what actually happens
    assert(a == 0b1111111111111110); // what would be safe
}

[...]

>

Do I corrupt memory here or not ?
Is that a safety violation ?

cast(bool*)&a is a safety violation.

The only safe values for a bool are 0 (false) and 1 (true). By creating a bool* that points to a different value, you have violated the language's safety invariants. Because of this, operations that would normally be safe (reading or writing through the bool*) may now result in undefined behavior.

June 05

On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote:

>

On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:
you have violated the language's safety invariants.

ah mais non.

June 05

On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:

>

question in the header, code in the body, execute on a X86 or X86_64 CPU

I understand that the notion of bool doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption.

Do I corrupt memory here or not ?
Is that a safety violation ?

The problem is that while setIt() is @safe, your main function is not. So the pointer cast (which is not @safe) is permitted.

A bool is a 1 byte type with two possible values : false (0) and true (1).

When you set the value to false, you write 0 to the byte it points to.

This is technically not a memory corruption, because as bool.sizeof < int.sizeof, you just write the low order byte of an int you allocated on the stack.

June 05

On Wednesday, 5 June 2024 at 05:15:42 UTC, Olivier Pisano wrote:

>

This is technically not a memory corruption, because as bool.sizeof < int.sizeof, you just write the low order byte of an int you allocated on the stack.

It was not an int, it was a ushort. Anyway, what I wrote still applies.

June 05
Basile B. kirjoitti 4.6.2024 klo 19.58:
> I understand that the notion of `bool` doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption.
> 
> Do I corrupt memory here or not ?
> Is that a safety violation ?
Viewing a valid boolean as an integer is still valid. Bit pattern of `false` is 0b0000_0000, and bit pattern of `true` is `0b0000_0001`. And even if the boolean is invalid, viewing it as an integer is probably valid if it was assigned to as an integer and not as an invalid boolean.

There's a related case though where the situation is unclear. How do `ubytes` other than 1 or 0, when viewed as bools? We probably can't say it's undefined behaviour, since it is allowed in `@safe`.

How I would define it, is that it's unspecific behaviour. That is if you have

```D
bool* unspecified = cast(bool*) new ubyte(0xff);
```

then

```
// same as void-initialising
bool a = *unspecified;
// also same as void-initialising
ubyte b = *unspecified;
// Reliably 0xff. It's using the memory slot as bool that makes it unspecified, but what's in the memory slot is not affected.
ubyte c = * cast(ubyte*) unspecified;

// Unspecified which happens. One and only one must happen though.
if (*unspecified) fun() else gun();

// Should this be required to call the same function as above? I'm not sure.
if (*unspecified) fun() else gun();
```


June 05

On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote:

>

The only safe values for a bool are 0 (false) and 1 (true).

AFAIK that was fixed and now full 8-bit range is safe.

June 05

On Wednesday, 5 June 2024 at 09:09:40 UTC, Kagamin wrote:

>

On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote:

>

The only safe values for a bool are 0 (false) and 1 (true).

AFAIK that was fixed and now full 8-bit range is safe.

cast(bool) someByte is fine - that doesn't reinterpret the bit representation.

The problem is certain values such as 0x2 for the byte representation can cause the boolean to be both true and false:
https://issues.dlang.org/show_bug.cgi?id=20148#c3

Void initialization of bool and bool union fields are now deprecated in @safe functions as of 2.109. There is a remaining case of casting an array to bool[], which I am working on disallowing in @safe.

« First   ‹ Prev
1 2