www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - ubyte array changing values between calls? Possible bug?

reply "Gary Willoughby" <dev nomad.so> writes:
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
Dec 13 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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.
Dec 13 2013
next sibling parent reply =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
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.
Dec 13 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
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.
Dec 14 2013
prev sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
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.
Dec 14 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Dec 14 2013
parent "Gary Willoughby" <dev nomad.so> writes:
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! :)
Dec 15 2013