Thread overview
Cycle detected between modules with ctors/dtors
Apr 23, 2011
Mandeep
Apr 23, 2011
Jonathan M Davis
Apr 23, 2011
Mandeep
Apr 24, 2011
Heinz
Apr 25, 2011
Mandeep
April 23, 2011
Hi,

I am trying to compile the code that was working with dmd 2.050 using dmd 2.052.

The code compiles but it gives me errors with message when trying to run:

Cycle detected between modules with ctors/dtors

This was not happening earlier with 2.050. I am not able to produce a smaller test case for this but it is happening with a lot of code pieces. A few scenarios in which this is happening is if a class passes its reference to child class for usage.

I understand that the above might not be a fit datapoint for analysis but wanted to understand if this is known or someone else has faced this?


Thanks & Regards
Mandeep
April 23, 2011
> Hi,
> 
> I am trying to compile the code that was working with dmd 2.050 using dmd 2.052.
> 
> The code compiles but it gives me errors with message when trying to run:
> 
> Cycle detected between modules with ctors/dtors
> 
> This was not happening earlier with 2.050. I am not able to produce a smaller test case for this but it is happening with a lot of code pieces. A few scenarios in which this is happening is if a class passes its reference to child class for usage.
> 
> I understand that the above might not be a fit datapoint for analysis but wanted to understand if this is known or someone else has faced this?

It happens when a module imports - directly or indirectly - another module which imports it - directly or indirectly - and they both have static constructors and/or static destructors (it _might_ not happen if one of them has static constructors but not static destructors and the other has static destructors and no static constructors, but if they both have either a static constructor or static destructor, it _will_ happen). This is because the compiler cannot determine which order to run the static constructors/destructors in. It doesn't know whether one depends on the other or whether the order matters, so it just doesn't accept it (though you usually get the error at runtime, not when it compiles; I'm not sure how or why you'd get it at compile time).

Now, why you weren't seeing the problem with dmd 2.050 but are now with dmd 2.052, I don't know. The solution is generally to either make it so that one of the modules doesn't have any static constructors or destructors or to offload the initialization to another module (such as std.stdio does with std.stdiobase) by having the new module's static constructor call a function in the original module to do the initialization for that module. But if you do that, you then have the responsibility to make sure that there isn't an actual circular dependency in the static constructors themselves, or you're going to run into trouble.

You can find discussions on how to solve the problem in the archives - probably on the D newsgroup.

- Jonathan M Davis
April 23, 2011
On 04/23/2011 02:04 PM, Jonathan M Davis wrote:
>> Hi,
>>
>> I am trying to compile the code that was working with dmd 2.050 using
>> dmd 2.052.
>>
>> The code compiles but it gives me errors with message when trying to run:
>>
>> Cycle detected between modules with ctors/dtors
>>
>> This was not happening earlier with 2.050. I am not able to produce a
>> smaller test case for this but it is happening with a lot of code
>> pieces. A few scenarios in which this is happening is if a class passes
>> its reference to child class for usage.
>>
>> I understand that the above might not be a fit datapoint for analysis
>> but wanted to understand if this is known or someone else has faced this?
>
> It happens when a module imports - directly or indirectly - another module
> which imports it - directly or indirectly - and they both have static
> constructors and/or static destructors (it _might_ not happen if one of them
> has static constructors but not static destructors and the other has static
> destructors and no static constructors, but if they both have either a static
> constructor or static destructor, it _will_ happen). This is because the
> compiler cannot determine which order to run the static
> constructors/destructors in. It doesn't know whether one depends on the other
> or whether the order matters, so it just doesn't accept it (though you usually
> get the error at runtime, not when it compiles; I'm not sure how or why you'd
> get it at compile time).
>
> Now, why you weren't seeing the problem with dmd 2.050 but are now with dmd
> 2.052, I don't know. The solution is generally to either make it so that one
> of the modules doesn't have any static constructors or destructors or to
> offload the initialization to another module (such as std.stdio does with
> std.stdiobase) by having the new module's static constructor call a function
> in the original module to do the initialization for that module. But if you do
> that, you then have the responsibility to make sure that there isn't an actual
> circular dependency in the static constructors themselves, or you're going to
> run into trouble.
>
> You can find discussions on how to solve the problem in the archives -
> probably on the D newsgroup.
>
> - Jonathan M Davis

Thanks, this worked for me. I shifted the code in the static constructor to another module and it works well now.

Regards
Mandeep
April 24, 2011
I haven't faced this myself. DMD is complaining about module Ctors and Dtors, so the bug must be there. But, i'm very curious about the scenario you mention, nested classes accessing its outer class:

How are you referring the parent class from the child classes?
Use the "outer" property of the child classes and see if that helps a bit.
April 25, 2011
On Sat, 23 Apr 2011 02:16:22 -0400, Mandeep <mandeep@brars.co.in> wrote:

> Hi,
>
> I am trying to compile the code that was working with dmd 2.050 using dmd 2.052.
>
> The code compiles but it gives me errors with message when trying to run:
>
> Cycle detected between modules with ctors/dtors

The cyclic module import code was changed significantly in 2.051, due to this bug:

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

I would appreciate if you think the cycle is not correct to post a case of where cycle detection is flagging a cycle that shouldn't be considered a cycle.

-Steve
April 25, 2011
On Sat, 23 Apr 2011 04:34:39 -0400, Jonathan M Davis <jmdavisProg@gmx.com> wrote:


> It happens when a module imports - directly or indirectly - another module
> which imports it - directly or indirectly - and they both have static
> constructors and/or static destructors (it _might_ not happen if one of them
> has static constructors but not static destructors and the other has static
> destructors and no static constructors, but if they both have either a static
> constructor or static destructor, it _will_ happen).

Note, the cyclic detection algorithm does not distinguish between these scenarios.  It does distinguish between thread local and shared ctor/dtors, but it just uses a single flag to denote having static constructors or destructors.

I think the reason might be that the runtime is supposed to run destructors in reverse order as constructors.  If it did the cycle detection independently, you would possibly have a different order for destruction.  I'm not sure it really matters.  It might be worth a bugzilla report/further discussion.

-Steve
April 25, 2011
On 04/25/2011 07:56 PM, Steven Schveighoffer wrote:
> On Sat, 23 Apr 2011 02:16:22 -0400, Mandeep <mandeep@brars.co.in> wrote:
>
>> Hi,
>>
>> I am trying to compile the code that was working with dmd 2.050 using
>> dmd 2.052.
>>
>> The code compiles but it gives me errors with message when trying to run:
>>
>> Cycle detected between modules with ctors/dtors
>
> The cyclic module import code was changed significantly in 2.051, due to
> this bug:
>
> http://d.puremagic.com/issues/show_bug.cgi?id=4384
>
> I would appreciate if you think the cycle is not correct to post a case
> of where cycle detection is flagging a cycle that shouldn't be
> considered a cycle.
>
> -Steve

The cases i could find were  pieces of bigger codebase with cycles coming out of more than 4-5 files with lot of code. I tried to repeat the code sequence with a couple of files with simplistic function but was not able to come out with a smaller test case for the above. Would try to come up with a test case again if i can. But i think moving around the code from static constructors as suggested in an earlier post in the thread helped.

Also, I think that the cyclic const/dest have a problem, because the same code was working find with 2.050.

Another bit of diff from my older scenario is that 2.050 was on 32 bit and i am using -m64 with 2.052, which i am not sure should be a problem.

Regards
Mandeep
April 25, 2011
On Mon, 25 Apr 2011 14:07:28 -0400, Mandeep <mandeep@brars.co.in> wrote:

> On 04/25/2011 07:56 PM, Steven Schveighoffer wrote:
>> On Sat, 23 Apr 2011 02:16:22 -0400, Mandeep <mandeep@brars.co.in> wrote:
>>
>>> Hi,
>>>
>>> I am trying to compile the code that was working with dmd 2.050 using
>>> dmd 2.052.
>>>
>>> The code compiles but it gives me errors with message when trying to run:
>>>
>>> Cycle detected between modules with ctors/dtors
>>
>> The cyclic module import code was changed significantly in 2.051, due to
>> this bug:
>>
>> http://d.puremagic.com/issues/show_bug.cgi?id=4384
>>
>> I would appreciate if you think the cycle is not correct to post a case
>> of where cycle detection is flagging a cycle that shouldn't be
>> considered a cycle.
>>
>> -Steve
>
> The cases i could find were  pieces of bigger codebase with cycles coming out of more than 4-5 files with lot of code. I tried to repeat the code sequence with a couple of files with simplistic function but was not able to come out with a smaller test case for the above. Would try to come up with a test case again if i can. But i think moving around the code from static constructors as suggested in an earlier post in the thread helped.
>
> Also, I think that the cyclic const/dest have a problem, because the same code was working find with 2.050.

The cyclic check is conservative, there is a very good possibility that the cyclic dependency does not alter the execution of the code at all.  So just because the code runs correctly does not mean that there is not a cycle.  All the cycle checker does is guarantee that the static constructors/destructors are executed in a sane order.  The compiler doesn't give enough info (and can't AFAIK) to tell if the cycle is harmful or not.

But if the cycle checker is identifying a cycle where there isn't one, I want to fix that.  It should be simple to verify, just follow the path listed in the exception and see if the cycle does exist.  If this is an error, you can email me privately, and I can help you reduce the test case.

> Another bit of diff from my older scenario is that 2.050 was on 32 bit and i am using -m64 with 2.052, which i am not sure should be a problem.

Although I have not tested the 64-bit compiler (not having a 64-bit linux box), I believe that the cyclic import check is the same.

-Steve