digitalmars.D.learn - String copying fails when output from assert
- David Zhang (17/17) Nov 21 2017 Hi,
- Adam D. Ruppe (5/8) Nov 21 2017 You're escaping a reference to a local variable there. chars[] is
- David Zhang (3/13) Nov 21 2017 So I'd have to allocate the buffer on the heap then...
- Jonathan M Davis (8/24) Nov 21 2017 Why would you need to allocate on the stack to allocate on the heap? If ...
- Jonathan M Davis (18/35) Nov 21 2017 Well, the assertion is going to throw an AssertError, which takes a stri...
- David Zhang (7/27) Nov 21 2017 Right. So a literal would work, because it's in the .data
- Jonathan M Davis (12/42) Nov 21 2017 Or any kind of exception message.
- Jonathan M Davis (4/47) Nov 21 2017 https://issues.dlang.org/show_bug.cgi?id=18002
- H. S. Teoh (8/27) Nov 21 2017 [...]
Hi, I've been trying to copy a string, then output it from an `assert(false)` statement, but the copy seems to be corrupted somehow. void main() { string str = "some string"; //initializing `chars` with any value doesn't do anything char[64] chars; //char[64] chars = '!'; //memcpy doesn't work either, though the output's different //import core.stdc.string; //memcpy(&chars[0], &str[0], str.length); chars[0..str.length] = str; assert(false, chars[0..str.length]); } What am I missing here?
Nov 21 2017
On Tuesday, 21 November 2017 at 18:49:40 UTC, David Zhang wrote:assert(false, chars[0..str.length]); } What am I missing here?You're escaping a reference to a local variable there. chars[] is a pointer to the stack, which is promptly smashed when the assert error starts working up the call chain, so by the time it actually prints, you have undefined behavior.
Nov 21 2017
On Tuesday, 21 November 2017 at 18:56:03 UTC, Adam D. Ruppe wrote:On Tuesday, 21 November 2017 at 18:49:40 UTC, David Zhang wrote:So I'd have to allocate the buffer on the heap then... Is there any way to do this without allocating to the stack?assert(false, chars[0..str.length]); } What am I missing here?You're escaping a reference to a local variable there. chars[] is a pointer to the stack, which is promptly smashed when the assert error starts working up the call chain, so by the time it actually prints, you have undefined behavior.
Nov 21 2017
On Tuesday, November 21, 2017 18:59:14 David Zhang via Digitalmars-d-learn wrote:On Tuesday, 21 November 2017 at 18:56:03 UTC, Adam D. Ruppe wrote:Why would you need to allocate on the stack to allocate on the heap? If you have a string to pass assert for its message, then just pass it the string. If you have a char[], then idup it. If you have a static array on the stack, then idup it. And if you're iduping in the assert statement, then it should only idup when the assertion fails. - Jonathan M DavisOn Tuesday, 21 November 2017 at 18:49:40 UTC, David Zhang wrote:So I'd have to allocate the buffer on the heap then... Is there any way to do this without allocating to the stack?assert(false, chars[0..str.length]); } What am I missing here?You're escaping a reference to a local variable there. chars[] is a pointer to the stack, which is promptly smashed when the assert error starts working up the call chain, so by the time it actually prints, you have undefined behavior.
Nov 21 2017
On Tuesday, November 21, 2017 18:49:40 David Zhang via Digitalmars-d-learn wrote:Hi, I've been trying to copy a string, then output it from an `assert(false)` statement, but the copy seems to be corrupted somehow. void main() { string str = "some string"; //initializing `chars` with any value doesn't do anything char[64] chars; //char[64] chars = '!'; //memcpy doesn't work either, though the output's different //import core.stdc.string; //memcpy(&chars[0], &str[0], str.length); chars[0..str.length] = str; assert(false, chars[0..str.length]); } What am I missing here?Well, the assertion is going to throw an AssertError, which takes a string for its message. It doesn't copy the contents of the string. It's just taking a slice just like whenever you pass a string to any other function. So, it refers to the same memory as what's passed in. So, if what it's passed is a string that refers to memory on the stack, then when it goes to print the message, it's going to be garbage, because the stack was unwound, and the static array is gone. Honestly, I'd argue that it's a bug that it allows you provide a message as a char[] instead of immutable(char)[]. It seems that the compiler is implicitly converting char[] to immutable(char)[] in this case, which is very bad. It would matter less if you were giving the assertion a char[] that referred to memory on the heap, but it still shouldn't be allowed. You really should be giving assertions a value that is an actual string that lives on the heap when providing a message, not a char[], and definitely not a char[] that's a slice of a static array. - Jonathan M Davis
Nov 21 2017
On Tuesday, 21 November 2017 at 19:05:21 UTC, Jonathan M Davis wrote:Well, the assertion is going to throw an AssertError, which takes a string for its message. It doesn't copy the contents of the string. It's just taking a slice just like whenever you pass a string to any other function. So, it refers to the same memory as what's passed in. So, if what it's passed is a string that refers to memory on the stack, then when it goes to print the message, it's going to be garbage, because the stack was unwound, and the static array is gone. Honestly, I'd argue that it's a bug that it allows you provide a message as a char[] instead of immutable(char)[]. It seems that the compiler is implicitly converting char[] to immutable(char)[] in this case, which is very bad. It would matter less if you were giving the assertion a char[] that referred to memory on the heap, but it still shouldn't be allowed. You really should be giving assertions a value that is an actual string that lives on the heap when providing a message, not a char[], and definitely not a char[] that's a slice of a static array. - Jonathan M DavisRight. So a literal would work, because it's in the .data segment, or inlined. Basically, only strings from the heap, or that are compiled into the code are valid for assert messages. What kind of behavior would an assert from stdc have (id, betterC)?
Nov 21 2017
On Tuesday, November 21, 2017 19:13:36 David Zhang via Digitalmars-d-learn wrote:On Tuesday, 21 November 2017 at 19:05:21 UTC, Jonathan M Davis wrote:Or any kind of exception message.Well, the assertion is going to throw an AssertError, which takes a string for its message. It doesn't copy the contents of the string. It's just taking a slice just like whenever you pass a string to any other function. So, it refers to the same memory as what's passed in. So, if what it's passed is a string that refers to memory on the stack, then when it goes to print the message, it's going to be garbage, because the stack was unwound, and the static array is gone. Honestly, I'd argue that it's a bug that it allows you provide a message as a char[] instead of immutable(char)[]. It seems that the compiler is implicitly converting char[] to immutable(char)[] in this case, which is very bad. It would matter less if you were giving the assertion a char[] that referred to memory on the heap, but it still shouldn't be allowed. You really should be giving assertions a value that is an actual string that lives on the heap when providing a message, not a char[], and definitely not a char[] that's a slice of a static array. - Jonathan M DavisRight. So a literal would work, because it's in the .data segment, or inlined. Basically, only strings from the heap, or that are compiled into the code are valid for assert messages.What kind of behavior would an assert from stdc have (id, betterC)?I don't know. It calls the C implementation at that point, so it won't throw an AssertError, but I don't know exactly how it's implemented. It probably just prints the message and then kills the program, so it'll probably work even with a slice of a static array, but I don't know for sure. However, unless the code is specifically versioned to only be betterC, it would be a really bad idea to rely on that behavior. And if assert ever gets fixed such that it properly rejects messages that aren't actually strings, passing it a char[] wouldn't work anymore anyway. - Jonathan M Davis
Nov 21 2017
On Tuesday, November 21, 2017 12:05:21 Jonathan M Davis via Digitalmars-d- learn wrote:On Tuesday, November 21, 2017 18:49:40 David Zhang via Digitalmars-d-learn wrote:https://issues.dlang.org/show_bug.cgi?id=18002 - Jonathan M DavisHi, I've been trying to copy a string, then output it from an `assert(false)` statement, but the copy seems to be corrupted somehow. void main() { string str = "some string"; //initializing `chars` with any value doesn't do anything char[64] chars; //char[64] chars = '!'; //memcpy doesn't work either, though the output's different //import core.stdc.string; //memcpy(&chars[0], &str[0], str.length); chars[0..str.length] = str; assert(false, chars[0..str.length]); } What am I missing here?Well, the assertion is going to throw an AssertError, which takes a string for its message. It doesn't copy the contents of the string. It's just taking a slice just like whenever you pass a string to any other function. So, it refers to the same memory as what's passed in. So, if what it's passed is a string that refers to memory on the stack, then when it goes to print the message, it's going to be garbage, because the stack was unwound, and the static array is gone. Honestly, I'd argue that it's a bug that it allows you provide a message as a char[] instead of immutable(char)[]. It seems that the compiler is implicitly converting char[] to immutable(char)[] in this case, which is very bad. It would matter less if you were giving the assertion a char[] that referred to memory on the heap, but it still shouldn't be allowed. You really should be giving assertions a value that is an actual string that lives on the heap when providing a message, not a char[], and definitely not a char[] that's a slice of a static array.
Nov 21 2017
On Tue, Nov 21, 2017 at 12:05:21PM -0700, Jonathan M Davis via Digitalmars-d-learn wrote:On Tuesday, November 21, 2017 18:49:40 David Zhang via Digitalmars-d-learn wrote:[...][...]char[64] chars; chars[0..str.length] = str; assert(false, chars[0..str.length]);Well, the assertion is going to throw an AssertError, which takes a string for its message. It doesn't copy the contents of the string. It's just taking a slice just like whenever you pass a string to any other function. So, it refers to the same memory as what's passed in. So, if what it's passed is a string that refers to memory on the stack, then when it goes to print the message, it's going to be garbage, because the stack was unwound, and the static array is gone. Honestly, I'd argue that it's a bug that it allows you provide a message as a char[] instead of immutable(char)[]. It seems that the compiler is implicitly converting char[] to immutable(char)[] in this case, which is very bad. It would matter less if you were giving the assertion a char[] that referred to memory on the heap, but it still shouldn't be allowed.Yeah, this is a bug. I filed an issue: https://issues.dlang.org/show_bug.cgi?id=18003 T -- The peace of mind---from knowing that viruses which exploit Microsoft system vulnerabilities cannot touch Linux---is priceless. -- Frustrated system administrator.
Nov 21 2017