digitalmars.D.learn - ldc executable crashes with this code
- forkit (19/19) Feb 02 2022 Any reason why compiling this with ldc would cause the exe to
- H. S. Teoh (12/14) Feb 02 2022 String literals are immutable by default. Casting immutable to mutable
- forkit (4/19) Feb 02 2022 that explains ldc perhaps (although i don't really get it. It's
- Basile B. (4/14) Feb 02 2022 your cast from immutable to mutable is an undefined behavior,
- Basile B. (10/28) Feb 02 2022 the D safe way :
- forkit (4/4) Feb 02 2022 On Thursday, 3 February 2022 at 01:39:33 UTC, forkit wrote:
- H. S. Teoh (14/34) Feb 02 2022 Assigning the literal to char[] simply creates a mutable slice of the
- forkit (3/3) Feb 02 2022 On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote:
- H. S. Teoh (7/10) Feb 02 2022 Mark your function @safe, and the compiler will stop you from unsafe
- forkit (8/17) Feb 02 2022 so i mark all my modules as @safe, by default.
- Steven Schveighoffer (8/11) Feb 03 2022 If you have a function that accepts mutable data, but you know for that
- Patrick Schluter (7/11) Feb 04 2022 would be nice if programmers (C or D) learnt that a typecast
- forkit (10/23) Feb 04 2022 In C, I would have no such expectation.
- forkit (6/19) Feb 04 2022 If I had wrote the code below, then I should not expect anything,
- Stanislav Blinov (11/15) Feb 04 2022 This is almost exactly what you have to do today, assuming you're
- H. S. Teoh (10/13) Feb 04 2022 Not to mention, casting to/from immutable is necessary in order to be
- forkit (8/14) Feb 04 2022 I concede ;-)
- bauss (26/41) Feb 07 2022 The compiler doesn't know what you think it knows in this
- Tejas (3/22) Feb 02 2022 This segfaults even on `dmd 2.098.0` for me.
- Steven Schveighoffer (16/50) Feb 03 2022 Note that on Windows DMD, string literals are not marked as Read only.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (6/6) Feb 03 2022 I know we are talking about something else but just to make sure, there
Any reason why compiling this with ldc would cause the exe to crash? Compiling with DMD (using either declaration of palindrome works just fine though) // ---- module test; import std; void main() { char[] palindrome = cast(char[])"able was I ere I saw elba"; //char[] palindrome = ['a','b','l','e','w','a','s','I','e','r','e','I','s','a','w','e','l','b','a']; writeln(palindrome); // note: The line below causes the exe to crash when compiled with ldc // but only if using the first version of palindrome. writeln(palindrome.reverse); } // ---
Feb 02 2022
On Wed, Feb 02, 2022 at 11:21:52PM +0000, forkit via Digitalmars-d-learn wrote: [...]char[] palindrome = cast(char[])"able was I ere I saw elba";String literals are immutable by default. Casting immutable to mutable is UB (Undefined Behaviour). [...]writeln(palindrome.reverse);Especially because .reverse mutates its argument. So you're attempting to overwrite immutable data here. That's probably what caused the crash: the literal is put in the read-only segment and the OS killed the program when it tried to write to data in that read-only segment. T -- People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird. -- D. Knuth
Feb 02 2022
On Wednesday, 2 February 2022 at 23:30:50 UTC, H. S. Teoh wrote:On Wed, Feb 02, 2022 at 11:21:52PM +0000, forkit via Digitalmars-d-learn wrote: [...]that explains ldc perhaps (although i don't really get it. It's cast to mutable and being assigned to mutable. in any case... ldc doesn't like it, but dmd is fine with this ??char[] palindrome = cast(char[])"able was I ere I saw elba";String literals are immutable by default. Casting immutable to mutable is UB (Undefined Behaviour). [...]writeln(palindrome.reverse);Especially because .reverse mutates its argument. So you're attempting to overwrite immutable data here. That's probably what caused the crash: the literal is put in the read-only segment and the OS killed the program when it tried to write to data in that read-only segment. T
Feb 02 2022
On Thursday, 3 February 2022 at 01:39:33 UTC, forkit wrote:On Wednesday, 2 February 2022 at 23:30:50 UTC, H. S. Teoh wrote:your cast from immutable to mutable is an undefined behavior, this may work or not.[...]that explains ldc perhaps (although i don't really get it. It's cast to mutable and being assigned to mutable. in any case... ldc doesn't like it, but dmd is fine with this ??Note that casting away a const qualifier and then mutating is undefined behavior, too, even when the referenced data is mutable. This is so that compilers and programmers can make assumptions based on const alone. For example, here it may be assumed that f does not alter x:(from https://dlang.org/spec/const3.html#removing_with_cast)
Feb 02 2022
On Thursday, 3 February 2022 at 01:51:34 UTC, Basile B. wrote:On Thursday, 3 February 2022 at 01:39:33 UTC, forkit wrote:the D safe way : ``` void main() safe { char[] palindrome = "able was I ere I saw elba".dup; writeln(palindrome); writeln(palindrome.reverse); } ```On Wednesday, 2 February 2022 at 23:30:50 UTC, H. S. Teoh wrote:your cast from immutable to mutable is an undefined behavior, this may work or not.[...]that explains ldc perhaps (although i don't really get it. It's cast to mutable and being assigned to mutable. in any case... ldc doesn't like it, but dmd is fine with this ??Note that casting away a const qualifier and then mutating is undefined behavior, too, even when the referenced data is mutable. This is so that compilers and programmers can make assumptions based on const alone. For example, here it may be assumed that f does not alter x:(from https://dlang.org/spec/const3.html#removing_with_cast)
Feb 02 2022
On Thursday, 3 February 2022 at 01:39:33 UTC, forkit wrote:oops! forgot the .dup char[] palindrome = cast(char[])"able was I ere I saw elba".dup; ;-)
Feb 02 2022
On Thu, Feb 03, 2022 at 01:39:33AM +0000, forkit via Digitalmars-d-learn wrote:On Wednesday, 2 February 2022 at 23:30:50 UTC, H. S. Teoh wrote:[...]On Wed, Feb 02, 2022 at 11:21:52PM +0000, forkit via Digitalmars-d-learn wrote: [...]char[] palindrome = cast(char[])"able was I ere I saw elba";String literals are immutable by default. Casting immutable to mutable is UB (Undefined Behaviour). [...]writeln(palindrome.reverse);Especially because .reverse mutates its argument. So you're attempting to overwrite immutable data here. That's probably what caused the crash: the literal is put in the read-only segment and the OS killed the program when it tried to write to data in that read-only segment.that explains ldc perhaps (although i don't really get it. It's cast to mutable and being assigned to mutable.Assigning the literal to char[] simply creates a mutable slice of the immutable data. That's technically UB. Then .reverse modifies the array in-place, which means you violated immutable.in any case... ldc doesn't like it, but dmd is fine with this ??UB doesn't mean a guaranteed crash, it means the result will be implementation-dependent (and likely not what was intended). It's possible that dmd didn't put the literal in a read-only segment, or there may be some other reason. In any case, just because it worked by chance does not mean it's OK to simply cast immutable to mutable and then proceed to mutate it. T -- Let X be the set not defined by this sentence...
Feb 02 2022
On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote:would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"
Feb 02 2022
On Thu, Feb 03, 2022 at 02:01:34AM +0000, forkit via Digitalmars-d-learn wrote: [...]would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"Mark your function safe, and the compiler will stop you from unsafe casts of this nature. That's part of the reason we have safe. ;-) T -- Everybody talks about it, but nobody does anything about it! -- Mark Twain
Feb 02 2022
On Thursday, 3 February 2022 at 03:25:39 UTC, H. S. Teoh wrote:On Thu, Feb 03, 2022 at 02:01:34AM +0000, forkit via Digitalmars-d-learn wrote: [...]so i mark all my modules as safe, by default. I commented it out though, so I could do the cast. Then realised I didn't need the cast at all, just the .dup now it's safe again. But safe or not, nothing good can come from casting an immutable string to a mutable string, and the compiler really should know that ;-)would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"Mark your function safe, and the compiler will stop you from unsafe casts of this nature. That's part of the reason we have safe. ;-) T
Feb 02 2022
On 2/3/22 12:53 AM, forkit wrote:But safe or not, nothing good can come from casting an immutable string to a mutable string, and the compiler really should know that ;-)If you have a function that accepts mutable data, but you know for that call it won't mutate the data (or maybe it's a C function that never mutates the data, but isn't attributed with const/immutable), then it is not UB. It's only UB to cast away immutable/const *and* mutate it. Reference: https://dlang.org/spec/const3.html#removing_with_cast -Steve
Feb 03 2022
On Thursday, 3 February 2022 at 02:01:34 UTC, forkit wrote:On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote:would be nice if programmers (C or D) learnt that a typecast means "shut up compiler I know what I do". You explicitly instructed the compiler to not complain. Remove the typecast and the compiler will bring an error. That's the reason why typecasts are to be avoided as much as possible.It is often a code smell.would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"
Feb 04 2022
On Friday, 4 February 2022 at 10:09:22 UTC, Patrick Schluter wrote:On Thursday, 3 February 2022 at 02:01:34 UTC, forkit wrote:In C, I would have no such expectation. The cast will occur whether I typed it in or not. My problem was, that I forgot the .dup For the compiler to allow me to cast from immutable to mutable (without the .dup), makes about as much sense as the compiler allowing this: int i; i = "Hello";On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote:would be nice if programmers (C or D) learnt that a typecast means "shut up compiler I know what I do". You explicitly instructed the compiler to not complain. Remove the typecast and the compiler will bring an error. That's the reason why typecasts are to be avoided as much as possible.It is often a code smell.would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"
Feb 04 2022
On Friday, 4 February 2022 at 10:09:22 UTC, Patrick Schluter wrote:On Thursday, 3 February 2022 at 02:01:34 UTC, forkit wrote:If I had wrote the code below, then I should not expect anything, whatsoever, from the compiler. () trustMe_I_am_a_complete_idiot { char[] palindrome = cast(char[])"able was I ere I saw elba"; } ();On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote:would be nice if programmers (C or D) learnt that a typecast means "shut up compiler I know what I do". You explicitly instructed the compiler to not complain. Remove the typecast and the compiler will bring an error. That's the reason why typecasts are to be avoided as much as possible.It is often a code smell.would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"
Feb 04 2022
On Friday, 4 February 2022 at 11:26:42 UTC, forkit wrote:If I had wrote the code below, then I should not expect anything, whatsoever, from the compiler. () trustMe_I_am_a_complete_idiot { char[] palindrome = cast(char[])"able was I ere I saw elba"; } ();This is almost exactly what you have to do today, assuming you're using safe. You'll **have** to write this then: `() trusted { auto palindrome = cast(char[])"able was I ere I saw elba"; } ();` Instead, you opted to comment out ` safe`. Unfortunately, " safe by default" idea was brutally eviscerated. As others have already stated, casting immutability away is something that has to be supported, e.g. to interface with const-agnostic APIs. ` safe` requires such casts to be more verbose, with good reason.
Feb 04 2022
On Fri, Feb 04, 2022 at 03:58:19PM +0000, Stanislav Blinov via Digitalmars-d-learn wrote: [...]As others have already stated, casting immutability away is something that has to be supported, e.g. to interface with const-agnostic APIs. ` safe` requires such casts to be more verbose, with good reason.Not to mention, casting to/from immutable is necessary in order to be able to implement D's GC in D. Basically, a cast is equivalent to telling the compiler "I know what I'm doing, don't complain". Generally casts should be avoided except under special circumstances. T -- Fact is stranger than fiction.
Feb 04 2022
On Friday, 4 February 2022 at 15:58:19 UTC, Stanislav Blinov wrote:.. ... As others have already stated, casting immutability away is something that has to be supported, e.g. to interface with const-agnostic APIs. ` safe` requires such casts to be more verbose, with good reason.I concede ;-) That the compiler knows this is safe: cast(char[])iStr.dup; and this is not safe: cast(char[])iStr; is sufficent.
Feb 04 2022
On Saturday, 5 February 2022 at 03:02:37 UTC, forkit wrote:On Friday, 4 February 2022 at 15:58:19 UTC, Stanislav Blinov wrote:The compiler doesn't know what you think it knows in this scenario. It doesn't know what function you intended to use originally, in this case .dup. So what do you expect the compiler to tell you when you do the following? ```d cast(char[])iStr ``` It's not actually invalid code and only invalid under safe IFF the result is mutated. To the compiler everything is actually fine in that scenario. The compiler also doesn't know that when you cast to char[] that you want to get a mutable duplicate of the string, because it doesn't have such a concept. It doesn't know .dup is actually the function you want to call, because there could be an ocean of different functions that you want to call that returns a mutable reference of the type. In fact by giving it a cast you tell the compiler "I know what type this really is" and thus the compiler just says "okay". It won't complain when you tell it you know what you're doing, similarly to calling a trusted function under safe, you tell the compiler "I know this function is safe, even though it's not marked as safe" and thus the compiler will not actually complain if the function wasn't safe... ... As others have already stated, casting immutability away is something that has to be supported, e.g. to interface with const-agnostic APIs. ` safe` requires such casts to be more verbose, with good reason.I concede ;-) That the compiler knows this is safe: cast(char[])iStr.dup; and this is not safe: cast(char[])iStr; is sufficent.
Feb 07 2022
On Wednesday, 2 February 2022 at 23:21:52 UTC, forkit wrote:Any reason why compiling this with ldc would cause the exe to crash? Compiling with DMD (using either declaration of palindrome works just fine though) // ---- module test; import std; void main() { char[] palindrome = cast(char[])"able was I ere I saw elba"; //char[] palindrome = ['a','b','l','e','w','a','s','I','e','r','e','I','s','a','w','e','l','b','a']; writeln(palindrome); // note: The line below causes the exe to crash when compiled with ldc // but only if using the first version of palindrome. writeln(palindrome.reverse); } // ---This segfaults even on `dmd 2.098.0` for me. Clearly implementation defined behavior.
Feb 02 2022
On 2/2/22 10:07 PM, Tejas wrote:On Wednesday, 2 February 2022 at 23:21:52 UTC, forkit wrote:Note that on Windows DMD, string literals are not marked as Read only. This is legacy from the D1 days when strings were actually typed as `char[]`. In fact, if you mutate the data, then it mutated the literal, so if you used the literal later, then you got the mutated version! e.g.: ```d auto str = "foo"; str[0] = 'b'; writeln("foo"); // outputs "boo" ``` On Linux, the literals were marked as ROM, and so you get a runtime fault. If you search back to the D1 days you can find posts about this difference between Windows and Linux. I'm assuming LDC and GDC follow the same practice as Linux DMD. -SteveAny reason why compiling this with ldc would cause the exe to crash? Compiling with DMD (using either declaration of palindrome works just fine though) // ---- module test; import std; void main() { char[] palindrome = cast(char[])"able was I ere I saw elba"; //char[] palindrome = ['a','b','l','e','w','a','s','I','e','r','e','I','s','a','w','e','l','b','a']; writeln(palindrome); // note: The line below causes the exe to crash when compiled with ldc // but only if using the first version of palindrome. writeln(palindrome.reverse); } // ---This segfaults even on `dmd 2.098.0` for me. Clearly implementation defined behavior.
Feb 03 2022
I know we are talking about something else but just to make sure, there is no need for the cast, copy, or .reverse: const palindrome = "able was I ere I saw elba"; writeln(palindrome); writeln(palindrome.retro); Ali
Feb 03 2022