Thread overview
ubyte array changing values between calls? Possible bug?
Dec 13, 2013
Gary Willoughby
Dec 13, 2013
John Colvin
Dec 13, 2013
Rémy Mouëza
Dec 14, 2013
John Colvin
Dec 14, 2013
Gary Willoughby
Dec 15, 2013
Ali Çehreli
Dec 15, 2013
Gary Willoughby
December 13, 2013
I have the following code which is massively simplified from a larger type. The problem occurs between assigning the value to the type and retrieving it.

The value is assigned through opAssign and the assert passes. When using a property to retrieve the same data the assert fails!

import std.bitmanip;
import std.stdio;
import std.traits;

struct IpAddress
{
	private ubyte[] _octets;

	this(uint value)
	{
		this.opAssign(value);
	}

	public @property ubyte[] data()
	{
		assert(this._octets == [1, 2, 3, 4]);
		return this._octets;
	}

	public void opAssign(uint value)
	{
		this._octets = value.nativeToBigEndian();
		assert(this._octets == [1, 2, 3, 4]);
	}
}

unittest
{
	auto ipAddress = IpAddress(0x01020304);
	assert(ipAddress.data == [1, 2, 3, 4]);
}

Any ideas why?

On a side note i also expected nativeToBigEndian to byte flip the hex literal, no idea why it hasn't, it's been a long day... I'm using MacOSX (Intel).

Compiled with: rdmd --force -de -debug -main -property -unittest -w file.d
December 13, 2013
On Friday, 13 December 2013 at 16:37:51 UTC, Gary Willoughby wrote:
> I have the following code which is massively simplified from a larger type. The problem occurs between assigning the value to the type and retrieving it.
>
> The value is assigned through opAssign and the assert passes. When using a property to retrieve the same data the assert fails!
>
> import std.bitmanip;
> import std.stdio;
> import std.traits;
>
> struct IpAddress
> {
> 	private ubyte[] _octets;
>
> 	this(uint value)
> 	{
> 		this.opAssign(value);
> 	}
>
> 	public @property ubyte[] data()
> 	{
> 		assert(this._octets == [1, 2, 3, 4]);
> 		return this._octets;
> 	}
>
> 	public void opAssign(uint value)
> 	{
> 		this._octets = value.nativeToBigEndian();
> 		assert(this._octets == [1, 2, 3, 4]);
> 	}
> }
>
> unittest
> {
> 	auto ipAddress = IpAddress(0x01020304);
> 	assert(ipAddress.data == [1, 2, 3, 4]);
> }
>
> Any ideas why?
>
> On a side note i also expected nativeToBigEndian to byte flip the hex literal, no idea why it hasn't, it's been a long day... I'm using MacOSX (Intel).
>
> Compiled with: rdmd --force -de -debug -main -property -unittest -w file.d

opAssign is escaping a reference to its stack by assigning the static array to the slice _octets. Therefore, garbage.
December 13, 2013
It works fine when using dup to the value returned by nativeToBigEndian:
    public void opAssign(uint value)
    {
        this._octets = value.nativeToBigEndian().dup;
        assert(this._octets == cast (ubyte[]) [1, 2, 3, 4]);
    }



On 12/13/2013 06:35 PM, John Colvin wrote:
> On Friday, 13 December 2013 at 16:37:51 UTC, Gary Willoughby wrote:
>> I have the following code which is massively simplified from a larger
>> type. The problem occurs between assigning the value to the type and
>> retrieving it.
>>
>> The value is assigned through opAssign and the assert passes. When
>> using a property to retrieve the same data the assert fails!
>>
>> import std.bitmanip;
>> import std.stdio;
>> import std.traits;
>>
>> struct IpAddress
>> {
>>     private ubyte[] _octets;
>>
>>     this(uint value)
>>     {
>>         this.opAssign(value);
>>     }
>>
>>     public @property ubyte[] data()
>>     {
>>         assert(this._octets == [1, 2, 3, 4]);
>>         return this._octets;
>>     }
>>
>>     public void opAssign(uint value)
>>     {
>>         this._octets = value.nativeToBigEndian();
>>         assert(this._octets == [1, 2, 3, 4]);
>>     }
>> }
>>
>> unittest
>> {
>>     auto ipAddress = IpAddress(0x01020304);
>>     assert(ipAddress.data == [1, 2, 3, 4]);
>> }
>>
>> Any ideas why?
>>
>> On a side note i also expected nativeToBigEndian to byte flip the hex
>> literal, no idea why it hasn't, it's been a long day... I'm using
>> MacOSX (Intel).
>>
>> Compiled with: rdmd --force -de -debug -main -property -unittest -w
>> file.d
>
> opAssign is escaping a reference to its stack by assigning the static
> array to the slice _octets. Therefore, garbage.

December 14, 2013
On Friday, 13 December 2013 at 18:01:53 UTC, Rémy Mouëza wrote:
>
> It works fine when using dup to the value returned by nativeToBigEndian:
>     public void opAssign(uint value)
>     {
>         this._octets = value.nativeToBigEndian().dup;
>         assert(this._octets == cast (ubyte[]) [1, 2, 3, 4]);
>     }
>

As expected, as dup allocates a new array on the heap.
December 14, 2013
On Friday, 13 December 2013 at 17:35:27 UTC, John Colvin wrote:
> On Friday, 13 December 2013 at 16:37:51 UTC, Gary Willoughby wrote:
>> I have the following code which is massively simplified from a larger type. The problem occurs between assigning the value to the type and retrieving it.
>>
>> The value is assigned through opAssign and the assert passes. When using a property to retrieve the same data the assert fails!
>>
>> import std.bitmanip;
>> import std.stdio;
>> import std.traits;
>>
>> struct IpAddress
>> {
>> 	private ubyte[] _octets;
>>
>> 	this(uint value)
>> 	{
>> 		this.opAssign(value);
>> 	}
>>
>> 	public @property ubyte[] data()
>> 	{
>> 		assert(this._octets == [1, 2, 3, 4]);
>> 		return this._octets;
>> 	}
>>
>> 	public void opAssign(uint value)
>> 	{
>> 		this._octets = value.nativeToBigEndian();
>> 		assert(this._octets == [1, 2, 3, 4]);
>> 	}
>> }
>>
>> unittest
>> {
>> 	auto ipAddress = IpAddress(0x01020304);
>> 	assert(ipAddress.data == [1, 2, 3, 4]);
>> }
>>
>> Any ideas why?
>>
>> On a side note i also expected nativeToBigEndian to byte flip the hex literal, no idea why it hasn't, it's been a long day... I'm using MacOSX (Intel).
>>
>> Compiled with: rdmd --force -de -debug -main -property -unittest -w file.d
>
> opAssign is escaping a reference to its stack by assigning the static array to the slice _octets. Therefore, garbage.

I'm not going to lie that has gone over my head a little. Could you explain it more simply please? I just want to totally understand the issue here. Thanks.
December 15, 2013
On 12/14/2013 10:48 AM, Gary Willoughby wrote:

> On Friday, 13 December 2013 at 17:35:27 UTC, John Colvin wrote:

>>>     public void opAssign(uint value)
>>>     {
>>>         this._octets = value.nativeToBigEndian();
>>>         assert(this._octets == [1, 2, 3, 4]);
>>>     }
>>> }

>> opAssign is escaping a reference to its stack by assigning the static
>> array to the slice _octets. Therefore, garbage.
>
> I'm not going to lie that has gone over my head a little. Could you
> explain it more simply please? I just want to totally understand the
> issue here. Thanks.

According to documentation, nativeToBigEndian returns a static array (fixed-length array):

  http://dlang.org/phobos/std_bitmanip.html#.nativeToBigEndian

It says "returns it as a ubyte[n] where n is the size of the given type."

Since static arrays normally live on the stack, the returned array is a local array.

As with any slice assignment, the assignment to this._octets in opAssign makes _octets a slice to the elements of that local array. Upon leaving opAssign that array is no more. So, _octets is left referring to elements that are long gone. :(

Ali

December 15, 2013
On Sunday, 15 December 2013 at 00:21:37 UTC, Ali Çehreli wrote:
> On 12/14/2013 10:48 AM, Gary Willoughby wrote:
>
> > On Friday, 13 December 2013 at 17:35:27 UTC, John Colvin
> wrote:
>
> >>>     public void opAssign(uint value)
> >>>     {
> >>>         this._octets = value.nativeToBigEndian();
> >>>         assert(this._octets == [1, 2, 3, 4]);
> >>>     }
> >>> }
>
> >> opAssign is escaping a reference to its stack by assigning
> the static
> >> array to the slice _octets. Therefore, garbage.
> >
> > I'm not going to lie that has gone over my head a little.
> Could you
> > explain it more simply please? I just want to totally
> understand the
> > issue here. Thanks.
>
> According to documentation, nativeToBigEndian returns a static array (fixed-length array):
>
>   http://dlang.org/phobos/std_bitmanip.html#.nativeToBigEndian
>
> It says "returns it as a ubyte[n] where n is the size of the given type."
>
> Since static arrays normally live on the stack, the returned array is a local array.
>
> As with any slice assignment, the assignment to this._octets in opAssign makes _octets a slice to the elements of that local array. Upon leaving opAssign that array is no more. So, _octets is left referring to elements that are long gone. :(
>
> Ali

Ah right, that now makes perfect sense. Thanks all! :)