Thread overview
[Issue 9335] New: Dtors are not called for dynamic arrays initialized by literals
Jan 17, 2013
Maxim Fomin
Jan 17, 2013
Maxim Fomin
Jun 25, 2013
Temtaime
Jun 28, 2013
yebblies
Jun 28, 2013
Temtaime
Jun 28, 2013
yebblies
Jun 28, 2013
Maxim Fomin
Jun 28, 2013
yebblies
January 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335

           Summary: Dtors are not called for dynamic arrays initialized by
                    literals
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: maxim@maxim-fomin.ru


--- Comment #0 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-01-17 08:34:20 PST ---
Dynamic arrays of structs initialized by array literals go out of scope without calling destructors. This does not happen with static arrays.

import std.stdio : writefln;

struct S
{
    int i;
    this(this) { writefln("%X postbit", i); i = 0;}
    ~this() { writefln("%X dtor", i); }
}

void main()
{
    S[] arr = [S()];
}

Issue is maked as dmd issue, because druntime cannot call destructors when AA array goes out of the scope.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335


monarchdodra@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra@gmail.com
           See Also|                            |http://d.puremagic.com/issu
                   |                            |es/show_bug.cgi?id=9334


--- Comment #1 from monarchdodra@gmail.com 2013-01-17 08:39:31 PST ---
(In reply to comment #0)
> Dynamic arrays of structs initialized by array literals go out of scope without calling destructors. This does not happen with static arrays.
> 
> import std.stdio : writefln;
> 
> struct S
> {
>     int i;
>     this(this) { writefln("%X postbit", i); i = 0;}
>     ~this() { writefln("%X dtor", i); }
> }
> 
> void main()
> {
>     S[] arr = [S()];
> }
> 
> Issue is maked as dmd issue, because druntime cannot call destructors when AA array goes out of the scope.

Same answer as in http://d.puremagic.com/issues/show_bug.cgi?id=9334.

The array is allocated dynamically, and makes no promises it will release at the end of the scope, or of the program.

I'm not sure what you mean by "array literals", but you'll get the same
behavior with:
S[] arr = new S[](5);

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335



--- Comment #2 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-01-17 10:07:54 PST ---
(In reply to comment #1)
> Same answer as in http://d.puremagic.com/issues/show_bug.cgi?id=9334.
> 
> The array is allocated dynamically, and makes no promises it will release at the end of the scope, or of the program.
> 
> I'm not sure what you mean by "array literals", but you'll get the same
> behavior with:
> S[] arr = new S[](5);

Well, situation here is different than in issue 9334

import core.stdc.stdio : printf;

struct S
{
    int i;
    this(this) { printf("%X postbit\n", i); i = 0;}
    ~this() { printf("%X dtor\n", i); }
}

void main()
{
    S[] arr = [S()];
}

Dump of assembler code for function _Dmain:
   0x0000000000418894 <+0>:    push   %rbp
   0x0000000000418895 <+1>:    mov    %rsp,%rbp
   0x0000000000418898 <+4>:    sub    $0x10,%rsp
   0x000000000041889c <+8>:    movabs $0x1,%rsi
   0x00000000004188a6 <+18>:    movabs $0x6362a0,%rdi
   0x00000000004188b0 <+28>:    callq  0x41a610 <_d_arrayliteralTX>
   0x00000000004188b5 <+33>:    xor    %ecx,%ecx
   0x00000000004188b7 <+35>:    mov    %ecx,-0x8(%rbp)
   0x00000000004188ba <+38>:    lea    -0x8(%rbp),%rsi
   0x00000000004188be <+42>:    mov    %rax,%rdi
   0x00000000004188c1 <+45>:    movsb  %ds:(%rsi),%es:(%rdi)
   0x00000000004188c2 <+46>:    movsb  %ds:(%rsi),%es:(%rdi)
   0x00000000004188c3 <+47>:    movsb  %ds:(%rsi),%es:(%rdi)
   0x00000000004188c4 <+48>:    movsb  %ds:(%rsi),%es:(%rdi)
   0x00000000004188c5 <+49>:    mov    %rax,%rdx
   0x00000000004188c8 <+52>:    movabs $0x1,%rax
   0x00000000004188d2 <+62>:    mov    %rcx,%rax
   0x00000000004188d5 <+65>:    leaveq
   0x00000000004188d6 <+66>:    retq
End of assembler dump.

Array literal is allocated by _d_arrayliteralTX, yet is initialized by a stack temporary S(). Where a dtor call on it? The behavior is in contrast to issue 9334 when a dtor in similar situation is called.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335


Temtaime <temtaime@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |temtaime@gmail.com


--- Comment #3 from Temtaime <temtaime@gmail.com> 2013-06-25 02:00:59 PDT ---
Dump.
Can someone fix that and 9334? It's critical bug for me.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335


yebblies <yebblies@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |yebblies@gmail.com
          Component|DMD                         |druntime


--- Comment #4 from yebblies <yebblies@gmail.com> 2013-06-28 22:43:04 EST ---
This is a druntime problem.  The destructor should be called for each element in the array when it is collected by the GC.

There is no need to call the destructor or postblit when moving the stack allocated structs to the heap, it is legal to move them with memcpy.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335



--- Comment #5 from Temtaime <temtaime@gmail.com> 2013-06-28 05:48:19 PDT ---
Stop. Why GC collects it?
Destructor should be called when declaration scope ends.
This is array of structs, not of classes.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335



--- Comment #6 from yebblies <yebblies@gmail.com> 2013-06-28 23:04:08 EST ---
(In reply to comment #5)
> Stop. Why GC collects it?
> Destructor should be called when declaration scope ends.
> This is array of structs, not of classes.

void main()
{
    S[] arr = [S()];
}

This is an array of structs, and the array is on the heap.

This would be an array on the stack:

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

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335


Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com


--- Comment #7 from Steven Schveighoffer <schveiguy@yahoo.com> 2013-06-28 07:11:09 PDT ---
The GC does not have any idea what type of data is in this block.  It cannot
call dtors, all it sees is a void * with no indication that it has a finalizer.
 In order for this to work, we need better record keeping by the GC.

It's definitely a druntime/GC problem, not a dmd problem.

Perhaps Rainer's precise GC stores enough information?  not sure.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335



--- Comment #8 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-06-28 07:42:41 PDT ---
(In reply to comment #4)
>
> There is no need to call the destructor or postblit when moving the stack allocated structs to the heap, it is legal to move them with memcpy.

Issue here is not in non-calling destructor when object is moved from stack to heap by pointer but is in non-calling destructor for temporary. This contradicts to policy in issue 9334 (which is itself not stable).

General problem here is that dmd (unexpectedly) sometimes initializes variables with temporaries and sometimes not. When it does initialize objects with a temporary, sometimes it calls destructors on it and sometimes not. Such game with temporaries and destructors causes bugs.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9335



--- Comment #9 from yebblies <yebblies@gmail.com> 2013-06-29 00:55:21 EST ---
(In reply to comment #8)
> (In reply to comment #4)
> >
> > There is no need to call the destructor or postblit when moving the stack allocated structs to the heap, it is legal to move them with memcpy.
> 
> Issue here is not in non-calling destructor when object is moved from stack to heap by pointer but is in non-calling destructor for temporary. This contradicts to policy in issue 9334 (which is itself not stable).
> 

The temporary you are talking about is the struct that is being moved to the heap.  D allows a struct to be moved with a memcpy.  9334 aside, what is happening here is valid.

1. Structs are constructed on the stack
2. Heap array space is allocated
3. Structs are bit-copied into the heap memory
4. The original stack structs are abandoned

Because only one copy of the structs exists at the end, there is no copy, only a move.

> General problem here is that dmd (unexpectedly) sometimes initializes > variables with temporaries and sometimes not. When it does initialize objects with a
temporary, sometimes it calls destructors on it and sometimes not. Such game
> with temporaries and destructors causes bugs.

dmd is free to choose either making a copy (which means calling the postblit, then the destructor of the temporary) or to do a move (bitcopy) like it is doing here.  The main difference is that a move has better performance.  Both are valid.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------