ubyte[] to string with @nogc - different behaviors

Steven Schveighoffer schveiguy at gmail.com
Wed Aug 5 20:28:22 UTC 2020


On 8/5/20 3:43 PM, Luhrel wrote:
> On Wednesday, 5 August 2020 at 18:46:19 UTC, Steven Schveighoffer wrote:
>> On 8/5/20 2:17 PM, Luhrel wrote:
>>> extern(D) string readString(ref const(ubyte)[] buffer) @nogc nothrow
>>> {
>>>      Array!ubyte bytes;
>>
>> Array is a reference counted type -- at the end of this scope, if 
>> there are no more references to it, it will *free the memory* being used.
>>
> 
> Oh, okay I see now.
> 
>>>
>>>      ubyte b = buffer.read!ubyte();
>>>      while (b)
>>>      {
>>>          bytes.insertBack(b);
>>>          b = buffer.read!ubyte();
>>>      }
>>>
>>>      if (bytes.length())
>>>      {
>>>          import core.stdc.stdio : printf;
>>>          import core.stdc.stdlib;
>>>
>>>          char* str_ptr = cast(char*)malloc(bytes.length() * 
>>> ubyte.sizeof);
>>>          string str = cast(string)str_ptr[0 .. bytes.length()];
>>>          str = cast(string)bytes[];
>>
>> Adam is right, you are not copying data here, just reassigning the 
>> reference.
>>
>> Not only that, but the expression bytes[] is not just a simple array, 
>> it's a range. I don't know what this does, but I wouldn't trust it.
> 
> It's a shortcut for bytes[0 .. bytes.length]

Oh crap. I was thinking this was std.container.array.Array. But it's 
rt.util.container.array.Array.

This is not reference counted, but does destroy its used memory on 
destruction.

So it's still the same problem. But the cast is not bad from what I can 
tell -- bytes[] returns a ubyte[].

If this were std.container.array.Array, it would not have compiled.

>>
>> What you likely want is:
>> str[] = bytes.data[];
> 
> Nope. I use the Array struct from rt.utils.container.array, which 
> doesn't have a `data` property.

Yep, my mistake. Wrong Array type.

But still, you are mallocing a block and throwing it away.

And I realize, this wouldn't have worked anyway, as str is a string, 
which means you can't overwrite the data.

I think there is likely a better way to do what you are trying to do.

> 
>>
>> This will copy all the data from the Array to the string.
>>
>> However, I don't really understand the point of this function. What 
>> does buffer.read!ubyte do?
>>
> 
> It returns the first ubyte in the `buffer`. Once read, the ubyte is 
> deleted from `buffer`.

OK, yeah I see the implementation in that file.

> 
>> If you have a more descriptive statement on what you want to 
>> accomplish, I'm sure it can be done in a simpler way than what you are 
>> trying to do here.
>>
> 
> I'm improving rt.backtrace.dwarf, specifically the readLineNumberProgram 
> function, which is @nogc, the source of all my problems :D.
> 
> DWARF v5 have a special DW_LNCT_path tag, which can be in the form 
> DW_FORM_string.
>  From the spec: "A string is a sequence of contiguous non-null bytes 
> followed by one null
> byte." - Commonly called a C string.
> 
> So, I need to read all non-null bytes in the buffer, until I found one. 
> But, as readLineNumberProgram is @nogc, it's kinda hard for me (I don't 
> come from C/C++).

What is the source of the incoming data? Will it be around by the time 
you need to use this string? Can you just slice it without copying? I'm 
not familiar with this code, so I don't know the requirements.

I would think:

return cast(const(char)[])buffer[0 .. strnlen(buffer.ptr, buffer.length))];

or something like that.

-Steve


More information about the Digitalmars-d mailing list