www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - bool passed by ref, safe or not ?

reply Basile B. <b2.temp gmx.com> writes:
question in the header, code in the body, execute on a X86 or 
X86_64 CPU

```d
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 ?
Jun 04
next sibling parent rkompass <rkompass gmx.de> writes:
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

 ```d
 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.
Jun 04
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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

 ```d
 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
Jun 04
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote:
 ```d
 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][1] 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. [1]: https://dlang.org/spec/function.html#safe-values
Jun 04
next sibling parent Basile B. <b2.temp gmx.com> writes:
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.
Jun 04
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
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.
Jun 05
parent Nick Treleaven <nick geany.org> writes:
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.
Jun 05
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
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:
 ```d
 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][1] 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. [1]: https://dlang.org/spec/function.html#safe-values
Obviously the topic was created because of the recent move D made. Sorry for the "catchy" aspect BTW. Now I remember that D safety is unrelated to undefined behaviors.
Jun 05
parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Wednesday, 5 June 2024 at 18:31:12 UTC, Basile B. wrote:
 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:
 ```d
 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][1] 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. [1]: https://dlang.org/spec/function.html#safe-values
Obviously the topic was created because of the recent move D made. Sorry for the "catchy" aspect BTW. Now I remember that D safety is unrelated to undefined behaviors.
I don’t think there’s any meaningful difference. If a program has UB, it can do anything, including corrupt memory. If a program corrupts memory, that’s UB. ` safe` means UB-free, which includes free of memory corruption.
Jun 06
prev sibling next sibling parent reply Olivier Pisano <olivier.pisano laposte.net> writes:
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.
Jun 04
parent Olivier Pisano <olivier.pisano laposte.net> writes:
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.
Jun 04
prev sibling parent Dukc <ajieskola gmail.com> writes:
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(); ```
Jun 05