D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 15009 - Object.destroy calls unnecessary postblits for destruction of static arrays object
Summary: Object.destroy calls unnecessary postblits for destruction of static arrays o...
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: druntime (show other issues)
Version: D2
Hardware: All All
: P1 major
Assignee: No Owner
URL:
Keywords: pull
Depends on:
Blocks:
 
Reported: 2015-09-03 18:01 UTC by forsaken
Modified: 2015-10-04 18:19 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description forsaken 2015-09-03 18:01:23 UTC
struct S {
    int x;
    this(int x) { writeln("ctor"); }
    this(this)  { writeln("ctor(postblit)"); }
    ~this()     { writeln("dtor"); }
}

void main(string[] args) {
    S[2]* arr = cast(S[2]*)calloc(1, S.sizeof);
    emplace(arr, S(1));
    destroy(*arr);
    free(arr);
}

output has 5 ctors, and 3 dtors:
  ctor
  ctor(postblit)
  ctor(postblit)
  dtor
  ctor(postblit)
  dtor
  ctor(postblit)
  dtor

fix is to modify this overload of Object.destroy:

void destroy(T : U[n], U, size_t n)(ref T obj)
  if (!is(T == struct))
{
    typeid(T).destroy(&obj);  // +++
    obj[] = U.init;
}

output now has 5 ctors, and 5 dtors, as expected:
  ctor
  ctor(postblit)
  ctor(postblit)
  dtor
  dtor
  dtor
  ctor(postblit)
  dtor
  ctor(postblit)
  dtor
Comment 1 Kenji Hara 2015-09-03 21:23:47 UTC
The bug in Object.destroy overload for the static array is, that is using block assignment.

void destroy(T : U[n], U, size_t n)(ref T obj)
  if (!is(T == struct))
{
    obj[] = U.init;
}

obj[] = U.init; _copies_ the rhs for each elements of lhs, and destroys the original elements of lhs. Instead of that, it should just destroy the elements.

And, the order of destroying should occur from the last to the first.

Then' the fixed destroy function should be:

void destroy(T : U[n], U, size_t n)(ref T obj)
  if (!is(T == struct))
{
    foreach_reverse (ref e; obj[])
        e = U.init;
}
Comment 2 Kenji Hara 2015-09-03 21:41:33 UTC
Note that, destroy actually calls destructors.

import std.stdio, std.conv, core.stdc.stdlib;
struct S {
    int x;
    this(int x) { writeln("ctor"); }
    this(this)  { writeln("ctor(postblit)"); }
    ~this()     { writeln("dtor"); }
}

void main(string[] args) {
    S[2]* arr = cast(S[2]*)calloc(1, S.sizeof);
    printf("-- calloc done\n");
    emplace(arr, S(1));
    printf("-- emplace done\n");
    destroy(*arr);
    printf("-- destroy done\n");
    //typeid(*arr).destroy(&arr);
    free(arr);
    printf("-- free done\n");
}

output is:

$ dmd -run test
-- calloc done
ctor
ctor(postblit)
ctor(postblit)
dtor
-- emplace done
ctor(postblit)
dtor
ctor(postblit)
dtor
-- destroy done
-- free done

My point is , the two postblit calls invoked by destroy() is unnecessary.
Comment 4 forsaken 2015-09-03 22:02:46 UTC
works as expected.
Thanks =)
Comment 5 github-bugzilla 2015-09-05 12:02:32 UTC
Commits pushed to master at https://github.com/D-Programming-Language/druntime

https://github.com/D-Programming-Language/druntime/commit/5be4156ccba77b49c7232060bbecb8b2527a8287
fix Issue 15009 - Object.destroy calls unnecessary postblits for destruction of static arrays object

https://github.com/D-Programming-Language/druntime/commit/3dc4e28ba997954deeb1f8db63051ba1f03e0463
Merge pull request #1376 from 9rnsr/fix15009

Issue 15009 - Object.destroy calls unnecessary postblits for destruction of static arrays object
Comment 6 github-bugzilla 2015-10-04 18:19:19 UTC
Commits pushed to stable at https://github.com/D-Programming-Language/druntime

https://github.com/D-Programming-Language/druntime/commit/5be4156ccba77b49c7232060bbecb8b2527a8287
fix Issue 15009 - Object.destroy calls unnecessary postblits for destruction of static arrays object

https://github.com/D-Programming-Language/druntime/commit/3dc4e28ba997954deeb1f8db63051ba1f03e0463
Merge pull request #1376 from 9rnsr/fix15009