www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Cycle detected between modules with ctors/dtors

reply "rumbu" <rumbu rumbu.ro> writes:
I encountered the following error:

First-chance exception: object.Exception Aborting: Cycle detected 
between modules with ctors/dtors:
system.globalization -> internals.locale -> 
system.runtime.interopservices -> system.io -> 
system.globalization at src\rt\minfo.d(162)

Only one of the listed modules has a static contructor  
(system.globalization) and that constructor doesn't use any 
information from other modules.

The message is not too helpful, I have no clue where to start 
searching for the error source, the source code has more than 25k 
LOC. In fact, I don't believe this error is true, since I have 
only two non-linked modules with static contructors.

Stack trace is also not helpful at all:

  	KernelBase.dll!7512f896	
  	sharp.exe!_D2rt9deh_win329throwImplFC6ObjectZv() + 0x1c bytes	D
  
	sharp.exe!_D2rt5minfo11ModuleGroup9sortCtorsMFZ4sortMFKAPyS6obj
ct10ModuleInfokZv() 
+ 0x27c bytes	D
  
	sharp.exe!_D2rt5minfo13rt_moduleCtorUZ14__foreachbody1MFKS2rt14sections_win
212SectionGroupZi() 
+ 0xf bytes	D
	sharp.exe!typeid(const(immutable(char)[]))() + 0xb020 bytes	D
Any hint is highly appreciated, at least I want to know where to start searching.
Mar 03 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/3/15 12:40 PM, rumbu wrote:
 I encountered the following error:

 First-chance exception: object.Exception Aborting: Cycle detected
 between modules with ctors/dtors:
 system.globalization -> internals.locale ->
 system.runtime.interopservices -> system.io -> system.globalization at
 src\rt\minfo.d(162)

 Only one of the listed modules has a static contructor
 (system.globalization) and that constructor doesn't use any information
 from other modules.
It's a complex problem. Because we don't control the linker, we cannot establish an order of execution for the module system. It must be a directed acyclic graph. Although, cycles are allowed that only involve a single module with ctor/dtors, or with no ctor/dtors. But we have to detect it at runtime during startup. two of those modules should have static ctor or dtor (they may have either to cause the error).
 The message is not too helpful, I have no clue where to start searching
 for the error source, the source code has more than 25k LOC. In fact, I
 don't believe this error is true, since I have only two non-linked
 modules with static contructors.
Just look for "static this" and "static ~this" inside those files identified.
 Stack trace is also not helpful at all:

       KernelBase.dll!7512f896
       sharp.exe!_D2rt9deh_win329throwImplFC6ObjectZv() + 0x1c bytes    D

      sharp.exe!_D2rt5minfo11ModuleGroup9sortCtorsMFZ4sortMFKAPyS6obj
ct10ModuleInfokZv() + 0x27c bytes    D

      sharp.exe!_D2rt5minfo13rt_moduleCtorUZ14__foreachbody1MFKS2rt14sections_win
212SectionGroupZi() + 0xf bytes    D
     sharp.exe!typeid(const(immutable(char)[]))() + 0xb020 bytes    D
The stack trace only shows the stack for when the DAG is being constructed, it is not a stack trace of trying to RUN those module ctors. -Steve
Mar 03 2015
parent reply "rumbu" <rumbu rumbu.ro> writes:
On Tuesday, 3 March 2015 at 18:55:49 UTC, Steven Schveighoffer 
wrote:

 Only one of the listed modules has a static contructor
 (system.globalization) and that constructor doesn't use any 
 information
 from other modules.
It's a complex problem. Because we don't control the linker, we cannot establish an order of execution for the module system. It must be a directed acyclic graph. Although, cycles are allowed that only involve a single module with ctor/dtors, or with no ctor/dtors. But we have to detect it at runtime during startup. two of those modules should have static ctor or dtor (they may have either to cause the error).
 The message is not too helpful, I have no clue where to start 
 searching
 for the error source, the source code has more than 25k LOC. 
 In fact, I
 don't believe this error is true, since I have only two 
 non-linked
 modules with static contructors.
Just look for "static this" and "static ~this" inside those files identified. -Steve
One of the listed modules had a ctor. Another one - curiously - not listed in the cyclic error - had a static dtor, and this module was imported by two of them. Anyway, reduced case scenario: module a; import b; static this(); ----- module b; import a; static ~this(); As I supposed, this is a false error, the order of execution seems very clear to me, but not for the runtime. Even if I have two ctors, I think it's better to relax this rule, maybe the constructors are not dependent one of each other to have cyclic errors. In my case, one of the constructors loads some resources bound to the executable and the destructor is simply a winapi call to CoUninitialize, totally unrelated.
Mar 03 2015
next sibling parent "rumbu" <rumbu rumbu.ro> writes:
Now I see: this "bug" is 7 years old, but is filled in for D1:

https://issues.dlang.org/show_bug.cgi?id=2457

Does this mean it will be ignored for D2?
Mar 03 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/3/15 4:24 PM, rumbu wrote:
 On Tuesday, 3 March 2015 at 18:55:49 UTC, Steven Schveighoffer wrote:

 Only one of the listed modules has a static contructor
 (system.globalization) and that constructor doesn't use any information
 from other modules.
It's a complex problem. Because we don't control the linker, we cannot establish an order of execution for the module system. It must be a directed acyclic graph. Although, cycles are allowed that only involve a single module with ctor/dtors, or with no ctor/dtors. But we have to detect it at runtime during startup. two of those modules should have static ctor or dtor (they may have either to cause the error).
 The message is not too helpful, I have no clue where to start searching
 for the error source, the source code has more than 25k LOC. In fact, I
 don't believe this error is true, since I have only two non-linked
 modules with static contructors.
Just look for "static this" and "static ~this" inside those files identified. -Steve
One of the listed modules had a ctor. Another one - curiously - not listed in the cyclic error - had a static dtor, and this module was imported by two of them.
curiously not listed? That doesn't make any sense. If there is not a cycle in the listed modules, where at least 2 modules have a static ctor or static dtor, then there is a bug in the cycle detection code.
 Anyway, reduced case scenario:

 module a;
 import b;
 static this();
 -----
 module b;
 import a;
 static ~this();

 As I supposed, this is a false error, the order of execution seems very
 clear to me, but not for the runtime. Even if I have two ctors, I think
 it's better to relax this rule, maybe the constructors are not dependent
 one of each other to have cyclic errors. In my case, one of the
 constructors loads some resources bound to the executable and the
 destructor is simply a winapi call to CoUninitialize, totally unrelated.
Clearly, the above is not an issue, but at the moment, the code treats having a ctor and having a dtor as the same thing. How to fix it? I'm not exactly sure, you need to have the modules sorted according to ctor and also according to dtor. The runtime is supposed to run dtors in reverse order from ctor calls, and I think we should not break that. But there is definitely room to allow for reordering when ctors are not affected. I'll have to think about it some more. -Steve
Mar 04 2015
next sibling parent reply "rumbu" <rumbu rumbu.ro> writes:
On Wednesday, 4 March 2015 at 16:08:00 UTC, Steven Schveighoffer 
wrote:

 curiously not listed? That doesn't make any sense. If there is 
 not a cycle in the listed modules, where at least 2 modules 
 have a static ctor or static dtor, then there is a bug in the 
 cycle detection code.
Source code is available here: https://github.com/rumbu13/sharp The runtime error chain was "system.globalization -> internals.locale -> system.runtime.interopservices -> system.io -> system.globalization Three of these modules import "internals.resources" containing a static constructor. The static dtor is in system.runtime.interopservices.
 Clearly, the above is not an issue, but at the moment, the code 
 treats having a ctor and having a dtor as the same thing. How 
 to fix it? I'm not exactly sure, you need to have the modules 
 sorted according to ctor and also according to dtor. The 
 runtime is supposed to run dtors in reverse order from ctor 
 calls, and I think we should not break that. But there is 
 definitely room to allow for reordering when ctors are not 
 affected.

 I'll have to think about it some more.

 -Steve
Why bother? I'll leave this to the programmer, he can take full responsibility to not mess up module ctors/dtors. I remember the old Delphi days where this was assumed from the start: initialization and finalization order of execution (equivalent of static ctor/dtor) were not guaranteed. It was better to obtain an AccessViolation or a StackOverflow and correct the circular reference, instead of a NEVER running executable.
Mar 04 2015
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/4/15 4:15 PM, rumbu wrote:
 On Wednesday, 4 March 2015 at 16:08:00 UTC, Steven Schveighoffer wrote:

 curiously not listed? That doesn't make any sense. If there is not a
 cycle in the listed modules, where at least 2 modules have a static
 ctor or static dtor, then there is a bug in the cycle detection code.
Source code is available here: https://github.com/rumbu13/sharp The runtime error chain was "system.globalization -> internals.locale -> system.runtime.interopservices -> system.io -> system.globalization Three of these modules import "internals.resources" containing a static constructor. The static dtor is in system.runtime.interopservices.
I'll take a look. importing a module that has static ctor/dtor doesn't count, it must be in the module itself to be part of the cycle.
 Clearly, the above is not an issue, but at the moment, the code treats
 having a ctor and having a dtor as the same thing. How to fix it? I'm
 not exactly sure, you need to have the modules sorted according to
 ctor and also according to dtor. The runtime is supposed to run dtors
 in reverse order from ctor calls, and I think we should not break
 that. But there is definitely room to allow for reordering when ctors
 are not affected.

 I'll have to think about it some more.
Why bother? I'll leave this to the programmer, he can take full responsibility to not mess up module ctors/dtors. I remember the old Delphi days where this was assumed from the start: initialization and finalization order of execution (equivalent of static ctor/dtor) were not guaranteed. It was better to obtain an AccessViolation or a StackOverflow and correct the circular reference, instead of a NEVER running executable.
Well, 1) because we can fix it, and it's the correct thing to do, and 2) because it's an interesting problem (I remember when I fixed the old cycle detection code, which was buggy and just printed "cycle detected" or some such nonsense, it was a very interesting difficult problem to solve). -Steve
Mar 06 2015
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Wed, 04 Mar 2015 11:06:50 -0500, Steven Schveighoffer wrote:

 Clearly, the above is not an issue, but at the moment, the code treats
 having a ctor and having a dtor as the same thing. How to fix it? I'm
 not exactly sure, you need to have the modules sorted according to ctor
 and also according to dtor. The runtime is supposed to run dtors in
 reverse order from ctor calls, and I think we should not break that. But
 there is definitely room to allow for reordering when ctors are not
 affected.
=20
 I'll have to think about it some more.
maybe do simply the thing you wrote, and have two independent lists. or,=20 strictly saying, four independent lists: for shared ctors, for static=20 ctors, for static dtors, for shared dtors.=
Mar 04 2015