Re: Segfault with std.container.Array but not regular dynamic array

2012-11-29 Thread Dan

On Thursday, 29 November 2012 at 15:06:07 UTC, Maxim Fomin wrote:

On Thursday, 29 November 2012 at 12:38:03 UTC, Dan wrote:
On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin 
wrote:


This doesn't look like assembly for previous source. Please 
provide the source for which you have assembly and tell which 
dmd options do you use.


Well, I'm using the latest dmd (from the trunk), phobos, 
druntime, so I could build and step through.




This is version generated by rdmd -version=bug --force 
--build-only -g -w -property. The only difference between this 
and yours is in <+71>.


<+00>:push   %rbp
<+01>:mov%rsp,%rbp
<+04>:sub$0x38,%rsp
<+08>:push   %rbx
// push 3 as a pkey, -0x30(%rbp) is 3
<+09>:mov$0x3,%eax
<+14>:mov%eax,-0x30(%rbp)
<+17>:lea-0x30(%rbp),%rcx
// push valuesize
<+21>:movabs $0x8,%rdx
// push keyti
<+31>:movabs $0x430f50,%rsi
// push map address, it is tls object
<+41>:mov%fs:0x0,%rdi
<+50>:add0x21e22f(%rip),%rdi# 0x636fb0
// call, keyti=8, aa=&map, valuesize=8, pkey=3
<+57>:callq  0x419140 <_aaGetX>
// store return value in -0x28(%rbp)
<+62>:mov%rax,-0x28(%rbp)
// check array bounds
<+66>:test   %rax,%rax
<+69>:jne0x418d99 <_Dmain+81>
<+71>:mov$0x13,%edi
<+76>:callq  0x418e28 <_D4main7__arrayZ>
// constructing S rhs for opAssign
<+81>:movabs $0x2a,%rax
<+91>:mov%rax,-0x18(%rbp) // rhs
<+95>:mov%rax,%rsi
// making this from -0x20(%rbp), but it was stored in 
-0x28(%rbp)

<+98>:lea-0x20(%rbp),%rdi
// opAssign loads this from %rdi
<+102>:   callq  0x418ce0 <_D4main1S8opAssignMFS4main1SZv>
// replace content in -0x28(%rbp) by -0x20(%rbp)
<+107>:   mov-0x20(%rbp),%rcx
<+111>:   mov-0x28(%rbp),%rdx
<+115>:   mov%rcx,(%rdx)
// load previously created object
<+118>:   movl   $0x3,-0x10(%rbp)
<+125>:   lea-0x10(%rbp),%rcx
<+129>:   movabs $0x8,%rdx
<+139>:   movabs $0x430f50,%rsi
<+149>:   mov%fs:0x0,%rax
<+158>:   mov0x21e1c3(%rip),%rbx# 0x636fb0
<+165>:   mov(%rax,%rbx,1),%rdi
<+169>:   callq  0x4192b8 <_aaGetRvalueX>
// store pointer to existed object
<+174>:   mov%rax,-0x8(%rbp)
// check array bounds
<+178>:   test   %rax,%rax
<+181>:   jne0x418e09 <_Dmain+193>
<+183>:   mov$0x14,%edi
<+188>:   callq  0x418e28 <_D4main7__arrayZ>
// load x member
<+193>:   mov-0x8(%rbp),%rcx
<+197>:   mov(%rcx),%rsi
<+200>:   movabs $0x430ac0,%rdi
<+210>:   xor%eax,%eax
<+212>:   callq  0x4188e0 
<+217>:   xor%eax,%eax
<+219>:   pop%rbx
<+220>:   leaveq
<+221>:   retq
End of assembler dump.

Main stack frame looks follows:
-0x30(%rbp):-0x28(%rbp) 3 as a pkey arg to _aaGetX
-0x28(%rbp):-0x20(%rbp) pointer to S allocated by _aaGetX
-0x20(%rbp):-0x18(%rbp) uninitialized struct - "this" ptr
-0x18(%rbp):-0x10(%rbp) constructed struct passed as rhs to 
opAssign

-0x10(%rbp):-0x08(%rbp) 3 as a pkey arg to _aaGetRvalueX
-0x08(%rbp):-0x00(%rbp) pointer to S returned from _aaGetRvalueX

It seems that dmd allocates space for two structs, one 
non-initialized, second initialized, issues call to druntime, 
then places a call to opAssign with non-initialized as "this" 
object with initialized as rhs argument, then writes content on 
non-initialized to allocated by druntime. So, this looks like a 
codegen bug.


By the way, if the code is compiled with command "dmd main -g 
-release -noboundscheck -version=bug", opAssign call is placed 
before calling _aaGetX.


Very educational - thanks!



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-29 Thread Maxim Fomin

On Thursday, 29 November 2012 at 12:38:03 UTC, Dan wrote:
On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin 
wrote:


This doesn't look like assembly for previous source. Please 
provide the source for which you have assembly and tell which 
dmd options do you use.


Well, I'm using the latest dmd (from the trunk), phobos, 
druntime, so I could build and step through.




This is version generated by rdmd -version=bug --force 
--build-only -g -w -property. The only difference between this 
and yours is in <+71>.


<+00>:push   %rbp
<+01>:mov%rsp,%rbp
<+04>:sub$0x38,%rsp
<+08>:push   %rbx
// push 3 as a pkey, -0x30(%rbp) is 3
<+09>:mov$0x3,%eax
<+14>:mov%eax,-0x30(%rbp)
<+17>:lea-0x30(%rbp),%rcx
// push valuesize
<+21>:movabs $0x8,%rdx
// push keyti
<+31>:movabs $0x430f50,%rsi
// push map address, it is tls object
<+41>:mov%fs:0x0,%rdi
<+50>:add0x21e22f(%rip),%rdi# 0x636fb0
// call, keyti=8, aa=&map, valuesize=8, pkey=3
<+57>:callq  0x419140 <_aaGetX>
// store return value in -0x28(%rbp)
<+62>:mov%rax,-0x28(%rbp)
// check array bounds
<+66>:test   %rax,%rax
<+69>:jne0x418d99 <_Dmain+81>
<+71>:mov$0x13,%edi
<+76>:callq  0x418e28 <_D4main7__arrayZ>
// constructing S rhs for opAssign
<+81>:movabs $0x2a,%rax
<+91>:mov%rax,-0x18(%rbp) // rhs
<+95>:mov%rax,%rsi
// making this from -0x20(%rbp), but it was stored in -0x28(%rbp)
<+98>:lea-0x20(%rbp),%rdi
// opAssign loads this from %rdi
<+102>:   callq  0x418ce0 <_D4main1S8opAssignMFS4main1SZv>
// replace content in -0x28(%rbp) by -0x20(%rbp)
<+107>:   mov-0x20(%rbp),%rcx
<+111>:   mov-0x28(%rbp),%rdx
<+115>:   mov%rcx,(%rdx)
// load previously created object
<+118>:   movl   $0x3,-0x10(%rbp)
<+125>:   lea-0x10(%rbp),%rcx
<+129>:   movabs $0x8,%rdx
<+139>:   movabs $0x430f50,%rsi
<+149>:   mov%fs:0x0,%rax
<+158>:   mov0x21e1c3(%rip),%rbx# 0x636fb0
<+165>:   mov(%rax,%rbx,1),%rdi
<+169>:   callq  0x4192b8 <_aaGetRvalueX>
// store pointer to existed object
<+174>:   mov%rax,-0x8(%rbp)
// check array bounds
<+178>:   test   %rax,%rax
<+181>:   jne0x418e09 <_Dmain+193>
<+183>:   mov$0x14,%edi
<+188>:   callq  0x418e28 <_D4main7__arrayZ>
// load x member
<+193>:   mov-0x8(%rbp),%rcx
<+197>:   mov(%rcx),%rsi
<+200>:   movabs $0x430ac0,%rdi
<+210>:   xor%eax,%eax
<+212>:   callq  0x4188e0 
<+217>:   xor%eax,%eax
<+219>:   pop%rbx
<+220>:   leaveq
<+221>:   retq
End of assembler dump.

Main stack frame looks follows:
-0x30(%rbp):-0x28(%rbp) 3 as a pkey arg to _aaGetX
-0x28(%rbp):-0x20(%rbp) pointer to S allocated by _aaGetX
-0x20(%rbp):-0x18(%rbp) uninitialized struct - "this" ptr
-0x18(%rbp):-0x10(%rbp) constructed struct passed as rhs to 
opAssign

-0x10(%rbp):-0x08(%rbp) 3 as a pkey arg to _aaGetRvalueX
-0x08(%rbp):-0x00(%rbp) pointer to S returned from _aaGetRvalueX

It seems that dmd allocates space for two structs, one 
non-initialized, second initialized, issues call to druntime, 
then places a call to opAssign with non-initialized as "this" 
object with initialized as rhs argument, then writes content on 
non-initialized to allocated by druntime. So, this looks like a 
codegen bug.


By the way, if the code is compiled with command "dmd main -g 
-release -noboundscheck -version=bug", opAssign call is placed 
before calling _aaGetX.


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-29 Thread Dan

On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin wrote:

This doesn't look like assembly for previous source. Please 
provide the source for which you have assembly and tell which 
dmd options do you use.


Well, I'm using the latest dmd (from the trunk), phobos, 
druntime, so I could build and step through.


rdmd -version=bug --force --build-only -g -w -property 
-I/home/dbdavidson/stage/vibe.d/source 
-I/home/dbdavidson/plusauri/dlang -L-levent_pthreads -L-levent 
-L-lssl -L-lcrypto /home/dbdavidson/tmp/again.d


dmd -v
DMD v2.061 DEBUG
DMD64 D Compiler v2.061

---
import core.stdc.stdio : printf;

struct S {
  long x = 42;
  version(bug) {
void opAssign(S rhs)
{
  printf("Assign %d\n", this.x);
}
  }
}

//alias RefCounted!(int) Foo;
alias S Foo;
Foo[int] map;

void main() {
  map[3] = Foo();
  printf("%d\n", map[3].x);
}



(gdb) disass
Dump of assembler code for function _Dmain:
   0x0041a630 <+0>:   push   %rbp
   0x0041a631 <+1>:   mov%rsp,%rbp
   0x0041a634 <+4>:   sub$0x38,%rsp
   0x0041a638 <+8>:   push   %rbx
=> 0x0041a639 <+9>:mov$0x3,%eax
   0x0041a63e <+14>:  mov%eax,-0x30(%rbp)
   0x0041a641 <+17>:  lea-0x30(%rbp),%rcx
   0x0041a645 <+21>:  movabs $0x8,%rdx
   0x0041a64f <+31>:  movabs $0x43cc10,%rsi
   0x0041a659 <+41>:  mov%fs:0x0,%rdi
   0x0041a662 <+50>:	add0x229957(%rip),%rdi# 
0x643fc0

   0x0041a669 <+57>:  callq  0x41ae84 <_aaGetX>
   0x0041a66e <+62>:  mov%rax,-0x28(%rbp)
   0x0041a672 <+66>:  test   %rax,%rax
   0x0041a675 <+69>:  jne0x41a681 <_Dmain+81>
   0x0041a677 <+71>:  mov$0x12,%edi
   0x0041a67c <+76>:  callq  0x41a710 <_D5again7__arrayZ>
   0x0041a681 <+81>:  movabs $0x2a,%rax
   0x0041a68b <+91>:  mov%rax,-0x18(%rbp)
   0x0041a68f <+95>:  mov%rax,%rsi
   0x0041a692 <+98>:  lea-0x20(%rbp),%rdi
   0x0041a696 <+102>:	callq  0x41a5c8 
<_D5again1S8opAssignMFS5again1SZv>

   0x0041a69b <+107>: mov-0x20(%rbp),%rcx
   0x0041a69f <+111>: mov-0x28(%rbp),%rdx
   0x0041a6a3 <+115>: mov%rcx,(%rdx)



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-29 Thread Maxim Fomin

On Wednesday, 28 November 2012 at 22:13:05 UTC, Dan wrote:
On Wednesday, 28 November 2012 at 20:30:41 UTC, Maxim Fomin 
wrote:

On Wednesday, 28 November 2012 at 18:08:59 UTC, Dan wrote:

This code with version=bug produces garbage because of 
opAssign. It seems that opAssign is actually called before 
accessing map:




Maxim, thanks for looking more at this. This bug is not 
affecting my work in any way - I'm just trying to learn more 
about D and how to debug, and your responses are helpful.


I've now built druntime and phobos with debug to see if I can 
see what is going on more.


For me the relevant assembly of your code looks like below. I 
see the value in the assoc array get created and memset 
initialized to 0 inside aaA.d function _aaGetX with this line:


memset(ptail + aligntsize(keytitsize), 0, valuesize); // 
zero value


Then between +62 and +102 it goes off the rails and upon entry 
to opAssign *this* is likely garbage. I can't be certain 
because the values I see are 0, which would be consistent with 
0 initialization - but could also just be luck. At this point I 
wish I knew some assembly. Anyway, I don't know if it is a 
problem with associative array code, per se, or the code 
generated by the compiler when opAssign and/or postblit are 
defined for the value type. I do know that if you have no 
postblit and no opAssign there are no issues - even with a 
destructor. This is consistent with the examples you have 
shown, they have postblit and/or opAssign as well as the 
RefCount code which has postblit and dtor. In both your example 
crash and the RefCount crash the actual seg fault is in the 
dtor accessing bogus data because as you pointed out it was not 
correctly initialized.


Thanks
Dan

 


This doesn't look like assembly for previous source. Please 
provide the source for which you have assembly and tell which dmd 
options do you use.


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Dan

On Wednesday, 28 November 2012 at 20:30:41 UTC, Maxim Fomin wrote:

On Wednesday, 28 November 2012 at 18:08:59 UTC, Dan wrote:

This code with version=bug produces garbage because of 
opAssign. It seems that opAssign is actually called before 
accessing map:




Maxim, thanks for looking more at this. This bug is not affecting 
my work in any way - I'm just trying to learn more about D and 
how to debug, and your responses are helpful.


I've now built druntime and phobos with debug to see if I can see 
what is going on more.


For me the relevant assembly of your code looks like below. I see 
the value in the assoc array get created and memset initialized 
to 0 inside aaA.d function _aaGetX with this line:


memset(ptail + aligntsize(keytitsize), 0, valuesize); // zero 
value


Then between +62 and +102 it goes off the rails and upon entry to 
opAssign *this* is likely garbage. I can't be certain because the 
values I see are 0, which would be consistent with 0 
initialization - but could also just be luck. At this point I 
wish I knew some assembly. Anyway, I don't know if it is a 
problem with associative array code, per se, or the code 
generated by the compiler when opAssign and/or postblit are 
defined for the value type. I do know that if you have no 
postblit and no opAssign there are no issues - even with a 
destructor. This is consistent with the examples you have shown, 
they have postblit and/or opAssign as well as the RefCount code 
which has postblit and dtor. In both your example crash and the 
RefCount crash the actual seg fault is in the dtor accessing 
bogus data because as you pointed out it was not correctly 
initialized.


Thanks
Dan

   0x0041a630 <+0>:   push   %rbp
   0x0041a631 <+1>:   mov%rsp,%rbp
   0x0041a634 <+4>:   sub$0x38,%rsp
   0x0041a638 <+8>:   push   %rbx
   0x0041a639 <+9>:   mov$0x3,%eax
   0x0041a63e <+14>:  mov%eax,-0x30(%rbp)
   0x0041a641 <+17>:  lea-0x30(%rbp),%rcx
   0x0041a645 <+21>:  movabs $0x8,%rdx
   0x0041a64f <+31>:  movabs $0x43cc10,%rsi
   0x0041a659 <+41>:  mov%fs:0x0,%rdi
   0x0041a662 <+50>:	add0x229957(%rip),%rdi# 
0x643fc0

   0x0041a669 <+57>:  callq  0x41ae84 <_aaGetX>
   0x0041a66e <+62>:  mov%rax,-0x28(%rbp)
   0x0041a672 <+66>:  test   %rax,%rax
   0x0041a675 <+69>:  jne0x41a681 <_Dmain+81>
   0x0041a677 <+71>:  mov$0x12,%edi
   0x0041a67c <+76>:  callq  0x41a710 <_D5again7__arrayZ>
=> 0x0041a681 <+81>:   movabs $0x2a,%rax
   0x0041a68b <+91>:  mov%rax,-0x18(%rbp)
   0x0041a68f <+95>:  mov%rax,%rsi
   0x0041a692 <+98>:  lea-0x20(%rbp),%rdi
   0x0041a696 <+102>:	callq  0x41a5c8 
<_D5again1S8opAssignMFS5again1SZv>




Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Maxim Fomin

On Wednesday, 28 November 2012 at 18:08:59 UTC, Dan wrote:
Thanks! I see what you are saying in valgrind. However, the 
following shows no problem in valgrind. Same code, only using S 
instead of RefCounted!(int).

How could that be explained?
Note that both RefCount!() and your posted S have opAssign, 
whereas the one below does not. Perhaps it is a problem only 
when there exists a custom opAssign?



Thanks
Dan




Because code does not access memory expected to be corrupted.

import core.stdc.stdio : printf;

struct S {
  long x = 42;
  version(bug) {
void opAssign(S rhs)
{
  printf("%d\n", this.x);
}
  }
}

//alias RefCounted!(int) Foo;
alias S Foo;
Foo[int] map;

void main() {
  map[3] = Foo();
  printf("%d\n", map[3].x);
}

This code with version=bug produces garbage because of opAssign. 
It seems that opAssign is actually called before accessing map:


push   %rbp
mov%rsp,%rbp
sub$0x28,%rsp
push   %rbx
movabs $0x2a,%rax
mov%rax,-0x10(%rbp)
mov%rax,%rsi
lea-0x18(%rbp),%rdi
callq  0x418c70 <_D3aux1S8opAssignMFS3aux1SZv>
mov-0x18(%rbp),%rcx
mov%rcx,-0x28(%rbp)
mov$0x3,%edx
mov%edx,-0x20(%rbp)
lea-0x20(%rbp),%rcx
mov$0x8,%dl
movabs $0x430db0,%rsi
mov%fs:0x0,%rdi
add0x21d2c1(%rip),%rdi# 0x635fb0
callq  0x419048 <_aaGetX>




Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Dan

On Wednesday, 28 November 2012 at 13:43:04 UTC, Maxim Fomin wrote:

On Wednesday, 28 November 2012 at 13:09:36 UTC, Dan wrote:


Actually bug is still there - changing unittest to main() does 
not fix program, even if it seems to run correctly. The problem 
with memory corruption is that it may happen with no observable 
segfaults just because erroneous operation was performed on 
memory which was permitted to be read/written.


Valgrind is tool which may show absence of memory corruption 
errors. Giving your example:


Thanks! I see what you are saying in valgrind. However, the 
following shows no problem in valgrind. Same code, only using S 
instead of RefCounted!(int).

How could that be explained?
Note that both RefCount!() and your posted S have opAssign, 
whereas the one below does not. Perhaps it is a problem only when 
there exists a custom opAssign?



Thanks
Dan

-
import std.typecons;
import std.stdio;
import pprint.pp;

struct S {
  int x;
  char[] c;
}
//alias RefCounted!(int) Foo;
alias S Foo;
Foo[int] map;

Foo f;

unittest {
  int i=3;
  map[i] = Foo();
}


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Joseph Rushton Wakeling

On 11/28/2012 02:09 PM, Dan wrote:

It would be interesting to know if Joseph was doing his "testing" out in
unittest or in a main.


In main -- the code you saw attached to my earlier email is the code I was 
running.

Thanks very much for your efforts at chasing down the bug!


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Maxim Fomin

On Wednesday, 28 November 2012 at 13:09:36 UTC, Dan wrote:
On Monday, 26 November 2012 at 15:44:42 UTC, Joseph Rushton 
Wakeling wrote:

Hello all,

I'm writing some code which is meant to represent a network of 
linked nodes.

[snip]

Ok, another follow up. I can reproduce your segfault using your 
posted code, it is included below. But the interesting thing 
is, I was doing the "testing" out of your Network!Node2 in a 
unittest section. By whittling down, the smallest crash case I 
could come up with is this:


import std.typecons;
import std.stdio;
alias RefCounted!(int) Foo;
unittest {
  Foo[int] map;
  map[1] = Foo();
}

When I change that unittest block to a 'void main()' it works 
just fine. I tried the same change of unittest to 'void main()' 
on your code and found the same results - no crash. I think the 
crash issue might not be with map (even though Maxim found some 
troubling stuff with uninitialized structs being destructed 
when inserting a key that is not present). Or maybe it is just 
a map problem and by switching to main I am just getting lucky 
in not getting a crash.




Actually bug is still there - changing unittest to main() does 
not fix program, even if it seems to run correctly. The problem 
with memory corruption is that it may happen with no observable 
segfaults just because erroneous operation was performed on 
memory which was permitted to be read/written.


Valgrind is tool which may show absence of memory corruption 
errors. Giving your example:


import std.typecons;
import std.stdio;
alias RefCounted!(int) Foo;

void main() { // main instead of unittest
  Foo[int] map;
  map[1] = Foo();
}

valgrind outputs:
==2562== Conditional jump or move depends on uninitialised 
value(s)
==2562==at 0x41A424: 
_D3std8typecons18__T10RefCountedTiZ10RefCounted6__dtorMFZv
==2562==by 0x41A4D5: 
_D3std8typecons18__T10RefCountedTiZ10RefCounted8opAssignMFS3std8typecons18__T10RefCountedTiZ10RefCountedZv

==2562==by 0x41A238: _Dmain
==2562==by 0x41C42B: 
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7runMainMFZv
==2562==by 0x41BCCD: 
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7tryExecMFMDFZvZv
==2562==by 0x41C472: 
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi6runAllMFZv
==2562==by 0x41BCCD: 
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7tryExecMFMDFZvZv

==2562==by 0x41BC89: _d_run_main
==2562==by 0x41BACA: main

which is exactly the same problem with unittest version: 
uninitialized object and bogus this pointer - now "this" just 
points to some allocated memory. Probably this happens because 
between running unittest and main function druntime has allocated 
more memory - and more memory is valid to be read.


Actually, I have also found this and considered to be not 
significant (bug still exists) and thus have not reported - next 
time I will be more verbose.


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Dan
On Monday, 26 November 2012 at 15:44:42 UTC, Joseph Rushton 
Wakeling wrote:

Hello all,

I'm writing some code which is meant to represent a network of 
linked nodes.

[snip]

Ok, another follow up. I can reproduce your segfault using your 
posted code, it is included below. But the interesting thing is, 
I was doing the "testing" out of your Network!Node2 in a unittest 
section. By whittling down, the smallest crash case I could come 
up with is this:


import std.typecons;
import std.stdio;
alias RefCounted!(int) Foo;
unittest {
  Foo[int] map;
  map[1] = Foo();
}

When I change that unittest block to a 'void main()' it works 
just fine. I tried the same change of unittest to 'void main()' 
on your code and found the same results - no crash. I think the 
crash issue might not be with map (even though Maxim found some 
troubling stuff with uninitialized structs being destructed when 
inserting a key that is not present). Or maybe it is just a map 
problem and by switching to main I am just getting lucky in not 
getting a crash.


It would be interesting to know if Joseph was doing his "testing" 
out in unittest or in a main.


Thanks
Dan

Here is the code that crashes. Change unittest to 'void main()' 
and it works??


---
import std.container;
import std.stdio;

struct Link {
  int id;
  this(int i) { id=i; }
}

struct Node1
{
  uint id;
  Link[] links;

  this(uint id)
  {
this.id = id;
  }

  void addLink(uint l)
  {
links ~= Link(l);
  }
}

struct Node2
{
  uint id;
  Array!(Link) links;

  this(uint id)
  {
this.id = id;
  }

  void addLink(uint l)
  {
links.insert(Link(l));
  }
}
struct Network(Node)
{
  Node[uint] nodes;

  void add(uint i, uint j)
  {
if((i in nodes) is null)
  nodes[i] = Node(i);
if((j in nodes) is null)
  nodes[j] = Node(j);

nodes[i].addLink(j);
nodes[j].addLink(i);
  }

  void print()
  {
foreach(k; nodes.keys)
  {
write("[", k, "]");
foreach(l; nodes[k].links)
  write(" ", l.id);
writeln();
  }
writeln();
  }
}

unittest {
  Network!Node2 net2;
  net2.add(1, 7);
  writeln(net2);
}



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-28 Thread Dan

On Tuesday, 27 November 2012 at 18:04:19 UTC, Maxim Fomin wrote:



I think it crashes because of using associative array. 
Assignment to an absent aa member causes memory allocation 
without proper object construction, and immediately after 
compiler issues call to opAssign for not-constructed object - 
that is why "this" pointer is "bogus" on entering function.




Thanks. Good troubleshooting.



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Maxim Fomin

On Tuesday, 27 November 2012 at 18:30:07 UTC, Ali Çehreli wrote:
Same problem under Linux. Somebody, please file this bug! Thank 
you! :)


Ali


http://d.puremagic.com/issues/show_bug.cgi?id=9084



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Ali Çehreli

On 11/27/2012 10:04 AM, Maxim Fomin wrote:

On Monday, 26 November 2012 at 22:42:53 UTC, Dan wrote:

On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton Wakeling
wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:


Ok, now I really want to know why it crashes. I've narrowed it down to
an example below. It seems there is a problem with RefCounted being
used as value in a map.




I think it crashes because of using associative array. Assignment to an
absent aa member causes memory allocation without proper object
construction, and immediately after compiler issues call to opAssign for
not-constructed object - that is why "this" pointer is "bogus" on
entering function.

import std.stdio;

struct S
{
int i = 42;
struct SS
{
int ii = 41;
this(this) { writeln("SS postblit"); }
void opAssign(SS rhs) { writeln("SS opAssign"); }
}
SS ss;
this(this) { writeln("S postblit"); }
void opAssign(S rhs)
{
writeln("S opAssign");
}
~this()
{
writefln("i=%d, ii=%d", i, ss.ii);
}
}

S[int] map ;
// S[2] map;
// S[] map = [S(), S()];

void main()
{
map[1] = S();
}

AA version on windows 2.060 prints

SS postblit
S opAssign
i=42, ii=41
i=4269990, ii=4269984 //garbage

Switching to dynamic or static array fixes the program.


Same problem under Linux. Somebody, please file this bug! Thank you! :)

Ali


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Maxim Fomin

On Monday, 26 November 2012 at 22:42:53 UTC, Dan wrote:
On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton 
Wakeling wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:


Ok, now I really want to know why it crashes. I've narrowed it 
down to an example below. It seems there is a problem with 
RefCounted being used as value in a map.





I think it crashes because of using associative array. Assignment 
to an absent aa member causes memory allocation without proper 
object construction, and immediately after compiler issues call 
to opAssign for not-constructed object - that is why "this" 
pointer is "bogus" on entering function.


import std.stdio;

struct S
{
int i = 42;
struct SS
{
int ii = 41;
this(this) { writeln("SS postblit"); }
void opAssign(SS rhs) { writeln("SS opAssign"); }
}
SS ss;
this(this) { writeln("S postblit"); }
void opAssign(S rhs)
{
writeln("S opAssign");
}
~this()
{
writefln("i=%d, ii=%d", i, ss.ii);
}
}

S[int] map ;
// S[2] map;
// S[] map = [S(), S()];

void main()
{
map[1] = S();
}

AA version on windows 2.060 prints

SS postblit
S opAssign
i=42, ii=41
i=4269990, ii=4269984 //garbage

Switching to dynamic or static array fixes the program.


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Joseph Rushton Wakeling

On 11/26/2012 11:42 PM, Dan wrote:

Ok, now I really want to know why it crashes. I've narrowed it down to an
example below. It seems there is a problem with RefCounted being used as value
in a map.


I don't have the expertise to understand the assembly, but just to note that 
even with all the structs converted to classes, nodes.d only compiles with dmd. 
 With ldmd2 or gdmd it exits with an error:


container.d:2248: Error: cannot compare const(Tuple!(uint,"id")[]) and 
const(Tuple!(uint,"id")[])


... regardless of whether Node1 and Node2 are declared as structs or classes.



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-26 Thread Dan
On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton 
Wakeling wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:


Ok, now I really want to know why it crashes. I've narrowed it 
down to an example below. It seems there is a problem with 
RefCounted being used as value in a map.


At the bottom I've included some dissassembly. If anyone can shed 
light and maybe suggest techniques for debugging that would be 
great. The issue is the assignment 'map[1] = Foo()' is calling 
into 'void opAssign(typeof(this) rhs)' of RefCounted!int. But 
upon entry the this pointer looks reasonable but the store is 
bogus:

(gdb) p this
$28 = (struct std.typecons.RefCounted!(int).RefCounted *) 
0x7fffd790

(gdb) p *this
$29 = {RefCounted = {_store = 0x}}

The rhs of the opAssign looks good:
p rhs
$30 = {RefCounted = {_store = 0x0}}

Any suggestions/pointers/ideas welcome.

Thanks
Dan

-
import std.typecons;
import std.stdio;

alias RefCounted!(int) Foo;
Foo[int] map;

unittest {
  map[1] = Foo();
}

Dump of assembler code for function _D3lnk11__unittest1FZv:
   0x0044367c <+0>:   push   %rbp
   0x0044367d <+1>:   mov%rsp,%rbp
   0x00443680 <+4>:   sub$0x38,%rsp
   0x00443684 <+8>:   push   %rbx
   0x00443685 <+9>:   movl   $0x1,-0x30(%rbp)
   0x0044368c <+16>:  lea-0x30(%rbp),%rcx
   0x00443690 <+20>:  movabs $0x8,%rdx
   0x0044369a <+30>:  movabs $0x481340,%rsi
   0x004436a4 <+40>:  mov%fs:0x0,%rdi
   0x004436ad <+49>:	add0x2478d4(%rip),%rdi# 
0x68af88

   0x004436b4 <+56>:  callq  0x44df08 <_aaGetX>
   0x004436b9 <+61>:  mov%rax,-0x28(%rbp)
   0x004436bd <+65>:  test   %rax,%rax
   0x004436c0 <+68>:	jne0x4436cc 
<_D3lnk11__unittest1FZv+80>

   0x004436c2 <+70>:  mov$0x8,%edi
   0x004436c7 <+75>:  callq  0x44c50c <_D3lnk7__arrayZ>
   0x004436cc <+80>:  sub$0x8,%rsp
   0x004436d0 <+84>:  xor%rax,%rax
   0x004436d3 <+87>:  mov%rax,-0x10(%rbp)
   0x004436d7 <+91>:  mov%rax,-0x18(%rbp)
   0x004436db <+95>:  lea-0x18(%rbp),%rbx
   0x004436df <+99>:  pushq  (%rbx)
   0x004436e1 <+101>: lea-0x20(%rbp),%rdi
   0x004436e5 <+105>:	callq  0x443d60 
<_D3std8typecons18__T10RefCountedTiZ10RefCounted8opAssignMFS3std8typecons18__T10RefCountedTiZ10RefCountedZv>

=> 0x004436ea <+110>:  add$0x10,%rsp
   0x004436ee <+114>: lea-0x20(%rbp),%rsi
   0x004436f2 <+118>: mov-0x28(%rbp),%rdi
   0x004436f6 <+122>: mov%rdi,-0x38(%rbp)
   0x004436fa <+126>: movsq  %ds:(%rsi),%es:(%rdi)
   0x004436fc <+128>: mov-0x38(%rbp),%rax
   0x00443700 <+132>: mov%rax,-0x8(%rbp)
   0x00443704 <+136>:	callq  0x44370b 
<_D3lnk11__unittest1FZv+143>
   0x00443709 <+141>:	jmp0x443715 
<_D3lnk11__unittest1FZv+153>

   0x0044370b <+143>: lea-0x20(%rbp),%rdi
   0x0044370f <+147>:	callq  0x443ce4 
<_D3std8typecons18__T10RefCountedTiZ10RefCounted6__dtorMFZv>

   0x00443714 <+152>: retq
   0x00443715 <+153>: pop%rbx
   0x00443716 <+154>: leaveq
   0x00443717 <+155>: retq
End of assembler dump.



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-26 Thread Dan
On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton 
Wakeling wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:
I'm a bit confused as to why.  By the look of things it's 
actually the creation
of new entries in the Node[uint] associative array, rather 
than appending links

to the individual nodes.  Can anyone advise?


I have noticed that changing Node1 and Node2 from structs to 
classes means the code no longer segfaults, so presumably it's 
something related to reference versus value types ... ?


I think it is probably more to do with the interplay of Array as 
a value type in a hash, as this produces the same crash.


--
import std.container;
unittest {
  alias Array!int IntArr;
  IntArr[int] map;
  map[1] = IntArr();
}


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-26 Thread Joseph Rushton Wakeling

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:

I'm a bit confused as to why.  By the look of things it's actually the creation
of new entries in the Node[uint] associative array, rather than appending links
to the individual nodes.  Can anyone advise?


I have noticed that changing Node1 and Node2 from structs to classes means the 
code no longer segfaults, so presumably it's something related to reference 
versus value types ... ?