Thread overview
Using emplace leading to memory corruption
Sep 29, 2013
d coder
Sep 29, 2013
monarch_dodra
Sep 29, 2013
Andrej Mitrovic
Sep 29, 2013
monarch_dodra
Sep 29, 2013
monarch_dodra
Sep 29, 2013
lomereiter
Sep 29, 2013
d coder
September 29, 2013
Greetings

I am trying to use emplace and it is seemingly leading to memory corruption. Before I file a bug on DMD Buzilla, I want to find out if I am doing something wrong or if it is a known issue. I am using a linux box and this testcase is freaky -- if I comment out either line 20 or line 24, the segfault vanishes.

Thanks
- Puneet

$ rdmd --force -version=EMPLACE -Isrc -J.. test.d
4000
Segmentation fault (core dumped)
$ rdmd --force -Isrc -J.. test.d
4000

struct bdd {}                                              // 01
class Frop {                                               // 02
  int[] _var;                                              // 03
  int[] var() {                                            // 04
    return _var;                                           // 05
  }                                                        // 06
  this() {                                                 // 07
    this._var.length = 1;                                  // 08
  }                                                        // 09
}                                                          // 10
class Foo {                                                // 11
  long[] nodes;                                            // 12
  Frop[] frops;                                            // 13
  long[] table;                                            // 14
  this() {                                                 // 15
    nodes.length = 120000;                                 // 16
    frops.length = 1;                                      // 17
    frops[0] = new Frop();                                 // 18
    initTable();                                           // 19
    zoo(frops[0].var);                                     // 20
  }                                                        // 21
  void initTable() {                                       // 22
    import std.stdio;                                      // 23
    writeln(4000);                                         // 24
    table.length = 40000;                                  // 25
  }                                                        // 26
  void zoo(int[] varset) {}                                // 27
}                                                          // 28
class Bar {                                                // 29
  Foo _foo;                                                // 30
  this() {                                                 // 31
    version(EMPLACE) {                                     // 32
      import std.conv, core.stdc.stdlib;                   // 33
      enum size_t size = __traits(classInstanceSize, Foo); // 34
      assert(size is 32);                                  // 35
      void* tmp = core.stdc.stdlib.malloc(size);           // 36
      if (!tmp)                                            // 37
        throw new Exception("Memory allocation failed");   // 38
      void[] mem = tmp[0..size];                           // 39
      _foo = emplace!(Foo)(mem);                           // 40
    }                                                      // 41
    else {                                                 // 42
      _foo = new Foo();                                    // 43
    }                                                      // 44
  }                                                        // 45
}                                                          // 46
void main() {                                              // 47
  auto bar = new Bar;                                      // 48
}                                                          // 49


September 29, 2013
On Sunday, 29 September 2013 at 07:03:30 UTC, d coder wrote:
> Greetings
>
> I am trying to use emplace and it is seemingly leading to memory
> corruption. Before I file a bug on DMD Buzilla, I want to find out if I am
> doing something wrong or if it is a known issue. I am using a linux box and
> this testcase is freaky -- if I comment out either line 20 or line 24, the
> segfault vanishes.
>
> Thanks
> - Puneet

I didn't see anything obviously wrong with your code.

Remember though that when emplacing a class over some memory, you must account for any extra alignment (though that doesn't seem to be a problem here).

Any chance you could simplify this and file it?
September 29, 2013
On 9/29/13, monarch_dodra <monarchdodra@gmail.com> wrote:
> Remember though that when emplacing a class over some memory, you must account for any extra alignment (though that doesn't seem to be a problem here).

emplace does do a check for misalignment this internally with the testEmplaceChunk helper function. It would throw otherwise.
September 29, 2013
On Sunday, 29 September 2013 at 09:46:04 UTC, Andrej Mitrovic wrote:
> On 9/29/13, monarch_dodra <monarchdodra@gmail.com> wrote:
>> Remember though that when emplacing a class over some memory, you
>> must account for any extra alignment (though that doesn't seem to
>> be a problem here).
>
> emplace does do a check for misalignment this internally with the
> testEmplaceChunk helper function. It would throw otherwise.

Right, emplace *checks*, which means caller must take it into account. This doesn't explain the issue, but it should be kept in mind when making the allocation, and building the slice. OP clearly just assumed his slice would be aligned.
September 29, 2013
On Sunday, 29 September 2013 at 08:21:34 UTC, monarch_dodra wrote:
> I didn't see anything obviously wrong with your code.

Did some more toying around. I did notice an issue in emplace, but nothing that would explain what you are observing.

By replacing your block with:

//----
    version(EMPLACE)
    {
      //Allocation
      import core.stdc.stdlib;
      enum size_t size = __traits(classInstanceSize, Foo);
      auto tmp = cast(byte*)core.stdc.stdlib.malloc(size);
      if (!tmp)
        throw new Exception("Memory allocation failed");
      assert (cast(size_t)tmp % 16 == 0);

      //Result
      auto result = cast(Foo)tmp;

      //Construction
      auto mem = tmp[0..size];
      auto init = typeid(Foo).init;
      assert(init.ptr);
      mem[] = init[];
      result.__ctor();

      //Finished building, assign
      _foo = result;
    }
//----

I'm observing the same behavior (Killed by signal 11).

I *think* the code is bug free, so I'm leaning towards a code gen bug.

Another thing I noticed is that if I call a class function on a null instance, I'm not getting a NullObjectError. I thought I was supposed to...?
September 29, 2013
You didn't tell GC that the allocated memory contains pointers to GC'd data.
Therefore, it thinks that the class members can be freed, which is not the case.

Adding lines
> import core.memory; GC.addRange(tmp, size);
resolves the problem. You must also call GC.removeRange(tmp) when you will free the allocated memory.

>       void[] mem = tmp[0..size];                           // 39
>       _foo = emplace!(Foo)(mem);                           // 40

September 29, 2013
On 9/29/13 5:29 AM, lomereiter wrote:
> You didn't tell GC that the allocated memory contains pointers to GC'd
> data.
> Therefore, it thinks that the class members can be freed, which is not
> the case.
>
> Adding lines
>> import core.memory; GC.addRange(tmp, size);
> resolves the problem. You must also call GC.removeRange(tmp) when you
> will free the allocated memory.
>
>>       void[] mem = tmp[0..size];                           // 39
>>       _foo = emplace!(Foo)(mem);                           // 40
>

I tried that and it still crashes. I don't think that's the problem. Puneet, the code looks legit, please file a bug report.

Andrei

September 29, 2013
> I tried that and it still crashes. I don't think that's the problem. Puneet, the code looks legit, please file a bug report.


Thanks for confirming.

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

Regards
- Puneet