Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
November 21, 2017 String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
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? |
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Zhang | 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.
|
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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:
>> 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.
So I'd have to allocate the buffer on the heap then...
Is there any way to do this without allocating to the stack?
|
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Zhang | 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
|
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 Davis
Right. 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)?
|
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
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: > > 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. https://issues.dlang.org/show_bug.cgi?id=18002 - Jonathan M Davis |
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
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. |
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Zhang | 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:
> > 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.
>
> So I'd have to allocate the buffer on the heap then...
> Is there any way to do this without allocating to the stack?
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 Davis
|
November 21, 2017 Re: String copying fails when output from assert | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Zhang | 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: > > 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 > > Right. 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. Or any kind of exception message. > 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 |
Copyright © 1999-2021 by the D Language Foundation