digitalmars.D - Using emplace leading to memory corruption
- d coder (62/62) Sep 28 2013 Greetings
- monarch_dodra (6/17) Sep 29 2013 I didn't see anything obviously wrong with your code.
- Andrej Mitrovic (3/6) Sep 29 2013 emplace does do a check for misalignment this internally with the
- monarch_dodra (6/15) Sep 29 2013 Right, emplace *checks*, which means caller must take it into
- monarch_dodra (32/33) Sep 29 2013 Did some more toying around. I did notice an issue in emplace,
- lomereiter (7/10) Sep 29 2013 You didn't tell GC that the allocated memory contains pointers to
- Andrei Alexandrescu (4/14) Sep 29 2013 I tried that and it still crashes. I don't think that's the problem.
- d coder (4/6) Sep 29 2013 Thanks for confirming.
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
Sep 28 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 - PuneetI 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?
Sep 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.
Sep 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: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.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.
Sep 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...?
Sep 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 linesimport 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
Sep 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 linesI tried that and it still crashes. I don't think that's the problem. Puneet, the code looks legit, please file a bug report. Andreiimport 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
Sep 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
Sep 29 2013