digitalmars.D.learn - bool passed by ref, safe or not ?
- Basile B. (22/22) Jun 04 question in the header, code in the body, execute on a X86 or
- rkompass (6/28) Jun 04 No everything is fine.
- Steven Schveighoffer (10/32) Jun 04 I don't think so. You passed an address to a bool, which uses 8
- Paul Backus (9/21) Jun 04 `cast(bool*)&a` is a safety violation.
- Basile B. (2/4) Jun 04 ah mais non.
- Kagamin (2/3) Jun 05 AFAIK that was fixed and now full 8-bit range is safe.
- Nick Treleaven (10/13) Jun 05 `cast(bool) someByte` is fine - that doesn't reinterpret the bit
- Basile B. (4/28) Jun 05 Obviously the topic was created because of the recent move D
- Quirin Schroll (5/36) Jun 06 I don’t think there’s any meaningful difference. If a program has
- Olivier Pisano (10/17) Jun 04 The problem is that while setIt() is @safe, your main function is
- Olivier Pisano (3/6) Jun 04 It was not an int, it was a ushort. Anyway, what I wrote still
- Dukc (27/33) Jun 05 Viewing a valid boolean as an integer is still valid. Bit pattern of
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
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
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
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
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
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
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:`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.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
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: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.```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 05
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: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.On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote: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.```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 06
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
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
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