Thread overview
Something wrong with GC
Mar 20, 2016
stunaep
Mar 20, 2016
rikki cattermole
Mar 21, 2016
thedeemon
Mar 22, 2016
stunaep
Mar 22, 2016
Edwin van Leeuwen
Mar 23, 2016
thedeemon
Mar 21, 2016
tsbockman
Mar 22, 2016
ag0aep6g
Mar 23, 2016
ag0aep6g
March 20, 2016
The gc throws invalid memory errors if I use Arrays from std.container.
For example, this throws an InvalidMemoryOperationError:
>import std.stdio;
>import std.container;
>
>void main() {
>	new Test();
>}
>
>class Test {
>	
>	private Array!string test = Array!string();
>	
>	this() {
>		test.insert("test");
>		writeln(test[0]);
>	}
>}

and here's the stack trace

>	testt.exe!app.onInvalidMemoryOperationError( void* _param_0 ) Line 21	D
> 	testt.exe!_D2gc2gc2GC134__T9runLockedS57_D2gc2gc2GC11removeRangeMFNbNiPvZ2goFNbNiPS2gc2gc3GcxPvZvS19_D2gc2gc9otherTimelS19_D2gc2gc9numOtherslTPS2gc2gc3GcxTPvZ9runLockedMFNbNiKPS2gc2gc3GcxKPvZv() + 0x52 bytes	D
> 	testt.exe!_D2gc2gc2GC11removeRangeMFNbNiPvZv() + 0x29 bytes	D
> 	testt.exe!gc_removeRange() + 0x21 bytes	D
> 	testt.exe!_D4core6memory2GC11removeRangeFNbNixPvZv() + 0xd bytes	D
> 	testt.exe!std.container.array.Array!string.Array.Payload.~this() Line 229 + 0x1f bytes	D
> 	testt.exe!object._destructRecurse!(std.container.array.Array!string.Array.Payload)._destructRecurse( std.container.array.Array!string.Array.Payload* s ) Line 2409 + 0xd bytes	D
> 	testt.exe!object.destroy!(std.container.array.Array!string.Array.Payload).destroy( std.container.array.Array!string.Array.Payload* obj ) Line 2778 + 0xd bytes	D
> 	testt.exe!std.typecons.RefCounted!(std.container.array.Array!string.Array.Payload, cast(RefCountedAutoInitialize)0).RefCounted.~this() Line 4864 + 0x10 bytes	D
> 	testt.exe!std.container.array.Array!string.Array.~this() Line 198 + 0x15 bytes	D
> 	testt.exe!app.Test.~this() Line 10 + 0x19 bytes	D
> 	testt.exe!rt_finalize2() + 0xb8 bytes	D
> 	testt.exe!rt_finalizeFromGC() + 0x24 bytes	D
> 	testt.exe!_D2gc2gc3Gcx5sweepMFNbZm() + 0x3a3 bytes	D
> 	testt.exe!_D2gc2gc3Gcx11fullcollectMFNbbZm() + 0x57a bytes	D
> 	testt.exe!_D2gc2gc2GC86__T9runLockedS56_D2gc2gc2GC18fullCollectNoStackMFNbZ2goFNbPS2gc2gc3GcxZmTPS2gc2gc3GcxZ9runLockedMFNbKPS2gc2gc3GcxZm() + 0x72 bytes	D
> 	testt.exe!_D2gc2gc2GC18fullCollectNoStackMFNbZv() + 0x11 bytes	D
> 	testt.exe!gc_term() + 0x14 bytes	D
> 	testt.exe!rt_term() + 0x9e bytes	D
> 	testt.exe!_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv() + 0x4d bytes	D
> 	testt.exe!_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv() + 0x6f bytes	D
> 	testt.exe!_d_run_main() + 0x419 bytes	D
> 	testt.exe!__entrypoint.main( int argc, char** argv ) + 0x22 bytes	D
> 	testt.exe!__tmainCRTStartup() Line 255 + 0x12 bytes	D
> 	kernel32.dll!0000000076cd59cd	
> 	ntdll.dll!0000000076f0b891	

Not sure what to do here
March 20, 2016
On 20/03/16 8:49 PM, stunaep wrote:
> The gc throws invalid memory errors if I use Arrays from std.container.
> For example, this throws an InvalidMemoryOperationError:
>> import std.stdio;
>> import std.container;
>>
>> void main() {
>>     new Test();
>> }
>>
>> class Test {
>>
>>     private Array!string test = Array!string();
>>
>>     this() {
>>         test.insert("test");
>>         writeln(test[0]);
>>     }
>> }
>
> and here's the stack trace
>
>>     testt.exe!app.onInvalidMemoryOperationError( void* _param_0 ) Line
>> 21    D
>>     testt.exe!_D2gc2gc2GC134__T9runLockedS57_D2gc2gc2GC11removeRangeMFNbNiPvZ2goFNbNiPS2gc2gc3GcxPvZvS19_D2gc2gc9otherTimelS19_D2gc2gc9numOtherslTPS2gc2gc3GcxTPvZ9runLockedMFNbNiKPS2gc2gc3GcxKPvZv()
>> + 0x52 bytes    D
>>     testt.exe!_D2gc2gc2GC11removeRangeMFNbNiPvZv() + 0x29 bytes    D
>>     testt.exe!gc_removeRange() + 0x21 bytes    D
>>     testt.exe!_D4core6memory2GC11removeRangeFNbNixPvZv() + 0xd bytes    D
>>     testt.exe!std.container.array.Array!string.Array.Payload.~this()
>> Line 229 + 0x1f bytes    D
>>     testt.exe!object._destructRecurse!(std.container.array.Array!string.Array.Payload)._destructRecurse(
>> std.container.array.Array!string.Array.Payload* s ) Line 2409 + 0xd
>> bytes    D
>>     testt.exe!object.destroy!(std.container.array.Array!string.Array.Payload).destroy(
>> std.container.array.Array!string.Array.Payload* obj ) Line 2778 + 0xd
>> bytes    D
>>     testt.exe!std.typecons.RefCounted!(std.container.array.Array!string.Array.Payload,
>> cast(RefCountedAutoInitialize)0).RefCounted.~this() Line 4864 + 0x10
>> bytes    D
>>     testt.exe!std.container.array.Array!string.Array.~this() Line 198
>> + 0x15 bytes    D
>>     testt.exe!app.Test.~this() Line 10 + 0x19 bytes    D
>>     testt.exe!rt_finalize2() + 0xb8 bytes    D
>>     testt.exe!rt_finalizeFromGC() + 0x24 bytes    D
>>     testt.exe!_D2gc2gc3Gcx5sweepMFNbZm() + 0x3a3 bytes    D
>>     testt.exe!_D2gc2gc3Gcx11fullcollectMFNbbZm() + 0x57a bytes    D
>>     testt.exe!_D2gc2gc2GC86__T9runLockedS56_D2gc2gc2GC18fullCollectNoStackMFNbZ2goFNbPS2gc2gc3GcxZmTPS2gc2gc3GcxZ9runLockedMFNbKPS2gc2gc3GcxZm()
>> + 0x72 bytes    D
>>     testt.exe!_D2gc2gc2GC18fullCollectNoStackMFNbZv() + 0x11 bytes    D
>>     testt.exe!gc_term() + 0x14 bytes    D
>>     testt.exe!rt_term() + 0x9e bytes    D
>>     testt.exe!_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv() +
>> 0x4d bytes    D
>>     testt.exe!_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv() +
>> 0x6f bytes    D
>>     testt.exe!_d_run_main() + 0x419 bytes    D
>>     testt.exe!__entrypoint.main( int argc, char** argv ) + 0x22
>> bytes    D
>>     testt.exe!__tmainCRTStartup() Line 255 + 0x12 bytes    D
>>     kernel32.dll!0000000076cd59cd
>>     ntdll.dll!0000000076f0b891
>
> Not sure what to do here

That looks like an error indeed.
But move the initialization of Array into the constructor.

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

March 21, 2016
On Sunday, 20 March 2016 at 07:49:17 UTC, stunaep wrote:
> The gc throws invalid memory errors if I use Arrays from std.container.

Those arrays are for RAII-style deterministic memory release, they shouldn't be freely mixed with GC-allocated things. What happens here is while initializing Array sees it got some GC-ed value type (strings), so it tells GC to look after those strings. When your program ends runtime does a GC cycle, finds your Test object, calls its destructor that calls Array destructor that tries to tell GC not to look at its data anymore. But during a GC cycle it's currently illegal to call such GC methods, so it throws an error.
Moral of this story: try not to store "managed" (collected by GC) types in Array and/or try not to have Arrays inside "managed" objects. If Test was a struct instead of a class, it would work fine.
March 21, 2016
On Sunday, 20 March 2016 at 07:49:17 UTC, stunaep wrote:
> The gc throws invalid memory errors if I use Arrays from std.container.
> ...
> Not sure what to do here

I don't know what your larger goal is, but maybe std.array.Appender would be a better fit?
March 22, 2016
On Monday, 21 March 2016 at 07:55:39 UTC, thedeemon wrote:
> On Sunday, 20 March 2016 at 07:49:17 UTC, stunaep wrote:
>> The gc throws invalid memory errors if I use Arrays from std.container.
>
> Those arrays are for RAII-style deterministic memory release, they shouldn't be freely mixed with GC-allocated things. What happens here is while initializing Array sees it got some GC-ed value type (strings), so it tells GC to look after those strings. When your program ends runtime does a GC cycle, finds your Test object, calls its destructor that calls Array destructor that tries to tell GC not to look at its data anymore. But during a GC cycle it's currently illegal to call such GC methods, so it throws an error.
> Moral of this story: try not to store "managed" (collected by GC) types in Array and/or try not to have Arrays inside "managed" objects. If Test was a struct instead of a class, it would work fine.

So what am I do to? Any other language can do such a thing so trivially... I also run into the same problem with emsi_containers TreeMap. It is imperative that I can store data such as

> public class Example1 {
>	
>	private File file;
>	
>	public this(File f) {
>		this.file = f;	
>	}
> }

or

> public class Example2 {
>	
>	private int one;
>	private int two;
>	
>	public this(int one, int two) {
>		this.one = one;
>		this.two = two;
>	}
> }

in a tree map and list of some sort. Neither of the above work whether they are classes or structs and it's starting to become quite bothersome...

March 22, 2016
On Tuesday, 22 March 2016 at 13:46:41 UTC, stunaep wrote:
>> public class Example2 {
>>	
>>	private int one;
>>	private int two;
>>	
>>	public this(int one, int two) {
>>		this.one = one;
>>		this.two = two;
>>	}
>> }
>
> in a tree map and list of some sort. Neither of the above work whether they are classes or structs and it's starting to become quite bothersome...

Is there a particular reason why you don't want to use the standard ranges?

public class Example2 {
	
	private int one;
	private int two;
	
	public this(int one, int two) {
		this.one = one;
		this.two = two;
	}
}

void main()
{
	auto myExamplesList = [ new Example2( 6,3 ), new Example2(7,5) ];
	
        // Note that if you do a lot of appending then using Appender is more performant than ~=
	myExamplesList ~= new Example2(9,1);
}

For trees there is also redBlackTree


March 22, 2016
On 20.03.2016 08:49, stunaep wrote:
> The gc throws invalid memory errors if I use Arrays from std.container.
> For example, this throws an InvalidMemoryOperationError:
>> import std.stdio;
>> import std.container;
>>
>> void main() {
>>     new Test();
>> }
>>
>> class Test {
>>
>>     private Array!string test = Array!string();
>>
>>     this() {
>>         test.insert("test");
>>         writeln(test[0]);
>>     }
>> }

I can reproduce the InvalidMemoryOperationError with git head dmd, but there doesn't seem to be a problem with 2.070. So I'd say this is a regression in the development version.

I've filed an issue: https://issues.dlang.org/show_bug.cgi?id=15821

You're probably building dmd/phobos from git, or you're using a nightly, right? Maybe you can go back to 2.070.2 until this is sorted out.
March 23, 2016
On Tuesday, 22 March 2016 at 13:46:41 UTC, stunaep wrote:
> So what am I do to?

Just learn more about available containers and their semantics. Maybe you don't need Array!T when there is a simple T[].
If you think you do need Array, then think about memory management: where are you going to allocate the data - in the GC heap or outside it. Depending on your answers there are different approaches. It's all solvable if you pause and think what exactly you're trying to do.

March 23, 2016
On 22.03.2016 16:56, ag0aep6g wrote:
> I've filed an issue: https://issues.dlang.org/show_bug.cgi?id=15821

And it's been fixed:
https://github.com/D-Programming-Language/druntime/pull/1519

Since the issue was a regression, the fix was made against the stable branch. It's going to be in the next release. But it's not yet in master, which means it's also not going to be in the nightlies for now.