By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,423 Members | 1,294 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,423 IT Pros & Developers. It's quick & easy.

atexit problems on statics inside mixed assembly after moving to VS2005

P: n/a
Aek
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
This occurs in static members / singletons (especially meyer type
singletons) which use locally declared static variables. These
variables are normally cleaned up automatically at shutdown of the
application by registering with the atexit. I break point the
destructor on a problem singleton class and notice that the destructor
of this static is called automatically *twice* with atexit. The second
call will cause the crash.

first automatic destruction (call stack):
ExecutableD.exe!GE::CShadowObjects::~CShadowObject s() Line 31 C++
ExecutableD.exe!`GE::CShadowObjects::GetInstance': :`2'::`dynamic
atexit destructor for 'g_ShadowObjects''() + 0xd bytes C++

second automatic destruction (call stack):
ExecutableD.exe!GE::CShadowObjects::~CShadowObject s() Line 31 C++
ExecutableD.exe!`GE::CShadowObjects::GetInstance': :`2'::`dynamic
atexit destructor for 'g_ShadowObjects''() + 0xd bytes C++

We notice that this singleton is implemented using a meyers singleton
that has a local static in the GetInstance() method and no specific
destroy call is needed. When I change the singleton to one that
contains a pointer to class and then call new in the GetInstance, then
it is fine. However I dont want to change tonnes of seemingly valid
code just to work around this crash.

We have no visible problems when we are running the application
outside of the IDE.

I believe it is a similar problem to this one described here:
http://groups.google.com.au/group/mi...5&rnum=3&hl=en

I think that perhaps it has something to do with the mix managed /
unmanaged code or perhaps it has something to do with using /
clr:oldSyntax and Managed Extensions for C++.

This page ( http://msdn2.microsoft.com/en-us/lib...68(VS.80).aspx
) suggests that the /clr option will provide support for "static
initialization of C++ variables in mixed images". Is this also true
then for /clr:oldSyntax ?

We have a number of native C++ libs (no clr) that are then linked into
an executable project built with /clr:oldSyntax. The executable
project contains Managed Extension C++ (hence the need for the
oldSyntax flag)
Ideally we will eventually get rid of Managed Extensions for C++ and
port to C++/CLI.
My main question is:
Could use of oldSyntax and Managed Extensions be a cause of the atexit
problems with static variables in a mixed assembly?

Any other suggestions?

Thankyou for your time
Josh

Jun 21 '07 #1
Share this Question
Share on Google+
20 Replies


P: n/a
Aek wrote:
My main question is:
Could use of oldSyntax and Managed Extensions be a cause of the atexit
problems with static variables in a mixed assembly?
It could be. Shouldn't be, but it's definitely the case that /clr was
tested a lot more carefully than /clr:oldSyntax for VS2005.
>
Any other suggestions?
Contact PSS. It sounds like you're looking at something complex and subtle
that may require inside knowledge to fully diagnose and understand.

-cd
Jun 21 '07 #2

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@x35g2000prf.googlegr oups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
This occurs in static members / singletons (especially meyer type
singletons) which use locally declared static variables. These
variables are normally cleaned up automatically at shutdown of the
application by registering with the atexit. I break point the
Are you doing the atexit registration in code, or the compiler is doing it
automatically?
destructor on a problem singleton class and notice that the destructor
of this static is called automatically *twice* with atexit. The second
call will cause the crash.

first automatic destruction (call stack):
ExecutableD.exe!GE::CShadowObjects::~CShadowObject s() Line 31 C++
ExecutableD.exe!`GE::CShadowObjects::GetInstance': :`2'::`dynamic
atexit destructor for 'g_ShadowObjects''() + 0xd bytes C++

second automatic destruction (call stack):
ExecutableD.exe!GE::CShadowObjects::~CShadowObject s() Line 31 C++
ExecutableD.exe!`GE::CShadowObjects::GetInstance': :`2'::`dynamic
atexit destructor for 'g_ShadowObjects''() + 0xd bytes C++

We notice that this singleton is implemented using a meyers singleton
that has a local static in the GetInstance() method and no specific
destroy call is needed. When I change the singleton to one that
contains a pointer to class and then call new in the GetInstance, then
it is fine. However I dont want to change tonnes of seemingly valid
code just to work around this crash.

We have no visible problems when we are running the application
outside of the IDE.

I believe it is a similar problem to this one described here:
http://groups.google.com.au/group/mi...5&rnum=3&hl=en

I think that perhaps it has something to do with the mix managed /
unmanaged code or perhaps it has something to do with using /
clr:oldSyntax and Managed Extensions for C++.

This page ( http://msdn2.microsoft.com/en-us/lib...68(VS.80).aspx
) suggests that the /clr option will provide support for "static
initialization of C++ variables in mixed images". Is this also true
then for /clr:oldSyntax ?

We have a number of native C++ libs (no clr) that are then linked into
an executable project built with /clr:oldSyntax. The executable
project contains Managed Extension C++ (hence the need for the
oldSyntax flag)
Ideally we will eventually get rid of Managed Extensions for C++ and
port to C++/CLI.
My main question is:
Could use of oldSyntax and Managed Extensions be a cause of the atexit
problems with static variables in a mixed assembly?

Any other suggestions?

Thankyou for your time
Josh

Jun 21 '07 #3

P: n/a
Aek
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@x35g2000prf.googlegr oups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
The compiler is generating the atexit registration automatically.

Thanks
Josh
Jun 22 '07 #4

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@j4g2000prf.googlegro ups.com...
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@x35g2000prf.googleg roups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.

The compiler is generating the atexit registration automatically.
Can you place a breakpoint on atexit and see if the cleanup code is
registered twice?

Are there multiple static objects in the same function, of which it would be
possible that only some are fully constructed due to exceptions?
>
Thanks
Josh

Jun 22 '07 #5

P: n/a
Aek
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@x35g2000prf.googlegr oups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
The atexit registration is automatically generated by the compiler.
After some experimenting yesterday, I found that if I rebuild one of
my problematic native C++ libs with the /clr:oldSyntax flag then the
problems with the statics in that lib are resolved. Problem is though
that one of the native libs is a graphics engine and it goes from real
time to slower than powerpoint with /clr enabled in the lib, so I
would like to leave the native C++ libs without clr.

Thankyou
Josh

Jun 22 '07 #6

P: n/a
Aek
On Jun 22, 10:44 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@j4g2000prf.googlegro ups.com...
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message
>news:11**********************@x35g2000prf.googleg roups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
The compiler is generating the atexit registration automatically.

Can you place a breakpoint on atexit and see if the cleanup code is
registered twice?
Yes I can, I just need to find where it is. Ill give it a go today.
Are there multiple static objects in the same function, of which it would be
possible that only some are fully constructed due to exceptions?
No, generally the problem is seen in functions that only have a single
static in the function. There seems to be the same problem with all
locally declared statics in native C++ libs (not just 1 case), so I do
not believe exceptions are occuring causing only some statics to be
fully constructed.

Thanks for your help so far.
Josh

Jun 22 '07 #7

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@e9g2000prf.googlegro ups.com...
On Jun 22, 10:44 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@j4g2000prf.googlegr oups.com...
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message
>>news:11**********************@x35g2000prf.google groups.com...
We recently moved our large codebase over from VS7 to 8 and found
that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.
The compiler is generating the atexit registration automatically.

Can you place a breakpoint on atexit and see if the cleanup code is
registered twice?

Yes I can, I just need to find where it is. Ill give it a go today.
>Are there multiple static objects in the same function, of which it would
be
possible that only some are fully constructed due to exceptions?

No, generally the problem is seen in functions that only have a single
static in the function. There seems to be the same problem with all
locally declared statics in native C++ libs (not just 1 case), so I do
not believe exceptions are occuring causing only some statics to be
fully constructed.
Ok, that was the only reason I could think of for having more than one
cleanup handler executed for the same function.

Oh... is there any possibility that the singleton is accessed from other
atexit handlers/static destructors?
>
Thanks for your help so far.
Josh
Jun 22 '07 #8

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11*********************@i38g2000prf.googlegro ups.com...
On Jun 22, 1:27 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>"Aek" <aek.muld...@gmail.comwrote in message

news:11**********************@x35g2000prf.googleg roups.com...
We recently moved our large codebase over from VS7 to 8 and found that
we now get access violations in atexit calls at shutdown when
debugging the application in VS2005.

The atexit registration is automatically generated by the compiler.
After some experimenting yesterday, I found that if I rebuild one of
my problematic native C++ libs with the /clr:oldSyntax flag then the
problems with the statics in that lib are resolved. Problem is though
that one of the native libs is a graphics engine and it goes from real
time to slower than powerpoint with /clr enabled in the lib, so I
would like to leave the native C++ libs without clr.
Can you open your assembly with .NET Reflector and make sure that the
SuppressUnmanagedCodeSecurityAttribute is applied?
>
Thankyou
Josh
Jun 22 '07 #9

P: n/a
Aek
On Jun 22, 10:44 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Can you place a breakpoint on atexit and see if the cleanup code is
registered twice?
I stepped through the local static creation and can confirm that the
atexit code for the local static is _not_ being called twice, but the
destructor is called twice on the same object.

-Josh

Jun 25 '07 #10

P: n/a
Aek
On Jun 25, 12:32 pm, Aek <aek.muld...@gmail.comwrote:
On Jun 22, 10:44 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Can you place a breakpoint on atexit and see if the cleanup code is
registered twice?

I stepped through the local static creation and can confirm that the
atexit code for the local static is _not_ being called twice, but the
destructor is called twice on the same object.

-Josh
Sorry I should clarify.
The atexit registration code ( __cdecl atexit ( _PVFV func ) is not
being called more than once on each local static,
but the atexit destruction is called twice on the same static objects
that have previously registered using __cdecl atexit ( _PVFV func )

thanks
Josh

Jun 25 '07 #11

P: n/a
Aek
On Jun 22, 11:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
"Aek" <aek.muld...@gmail.comwrote in message

news:11*********************@i38g2000prf.googlegro ups.com...
I found something interesting today that I overlooked before.
The call stack of the atexit calls is showing _cexit calls coming from
different assemblies.
Sorry if this callstack cut and paste comes out a garbled mess in your
reader.. it basically shows that
ConsoleServer_d.dll is calling msvcr80d.dll!_cexit(), which cleans up
the local static... then
ExecuteD.exe calls msvcr80d.dll!_cexit() which again tries to clean up
the local static.

Interesting. ExecuteD.exe is what is run and consoleserver_d.dll is a
dll that it uses. At least now I have somewhere to focus my attention.

Feel free to drop in any thoughts you have about this now, with this
new information.
> ExecuteD.exe!OSMonitor::~OSMonitor() Line 35 C++
ExecuteD.exe!`OSMonitor::GetInstance'::`2'::`dynam ic atexit
destructor for 'instance''() + 0xd bytes C++
msvcr80d.dll!doexit(int code=0, int quick=0, int retcaller=1) Line
553 C
msvcr80d.dll!_cexit() Line 413 + 0xb bytes C
[External Code]
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::_Unin itializeDefaultDomain(void*
cookie = <undefined value>) Line 713 C++
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::Unini tializeDefaultDomain()
Line 729 + 0x8 bytes C++
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::Domai nUnload(System::Object^
source = 0x048ef89c, System::EventArgs^ arguments = <undefined value>)
Line 762 C++
msvcm80d.dll!
<CrtImplementationDetails>::ModuleUninitializer::S ingletonDomainUnload(System::Object^
source = 0x048ef8bc, System::EventArgs^ arguments = <undefined value>)
Line 303 + 0x57 bytes C++
[Frames below may be incorrect and/or missing, no symbols loaded for
mscorwks.dll]
ntdll.dll!7c90e57c()
kernel32.dll!7c80a027()
kernel32.dll!7c80b683()

> ExecuteD.exe!OSMonitor::~OSMonitor() Line 35 C++
ExecuteD.exe!`OSMonitor::GetInstance'::`2'::`dynam ic atexit
destructor for 'instance''() + 0xd bytes C++
msvcr80d.dll!doexit(int code=0, int quick=0, int retcaller=1) Line
553 C
msvcr80d.dll!_cexit() Line 413 + 0xb bytes C
[External Code]
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::_Unin itializeDefaultDomain(void*
cookie = <undefined value>) Line 713 C++
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::Unini tializeDefaultDomain()
Line 729 + 0x8 bytes C++
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::Domai nUnload(System::Object^
source = 0x048ef89c, System::EventArgs^ arguments = <undefined value>)
Line 762 C++
msvcm80d.dll!
<CrtImplementationDetails>::ModuleUninitializer::S ingletonDomainUnload(System::Object^
source = 0x048ef8bc, System::EventArgs^ arguments = <undefined value>)
Line 303 + 0x57 bytes C++
[Frames below may be incorrect and/or missing, no symbols loaded for
mscorwks.dll]
ntdll.dll!7c90e57c()
kernel32.dll!7c80a027()
kernel32.dll!7c80b683()

Regards,
Josh

Jun 25 '07 #12

P: n/a
Aek
On Jun 22, 11:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Can you open your assembly with .NET Reflector and make sure that the
SuppressUnmanagedCodeSecurityAttribute is applied?
The SuppressUnmanagedCodeSecurityAttribute was not applied to the dll
(ConsoleServerD.dll) or the executable (ExecuteD.exe)
I have applied it now and will investigate the results.

Thanks
Josh
Jun 25 '07 #13

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@a26g2000pre.googlegr oups.com...
On Jun 22, 11:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>"Aek" <aek.muld...@gmail.comwrote in message

news:11*********************@i38g2000prf.googlegr oups.com...

I found something interesting today that I overlooked before.
The call stack of the atexit calls is showing _cexit calls coming from
different assemblies.
Sorry if this callstack cut and paste comes out a garbled mess in your
reader.. it basically shows that
ConsoleServer_d.dll is calling msvcr80d.dll!_cexit(), which cleans up
the local static... then
ExecuteD.exe calls msvcr80d.dll!_cexit() which again tries to clean up
the local static.
This seems very important.

I think I'm actually running into a related problem.... the "attempted to
initialize CRT more than once" runtime error. I was looking through the
source code where that error message was generated, and found comments
talking about process-wide state which looked very module-local to me (there
was no __declspec dllimport). Let me see if I can find the particular spot
again.
>
Interesting. ExecuteD.exe is what is run and consoleserver_d.dll is a
dll that it uses. At least now I have somewhere to focus my attention.

Feel free to drop in any thoughts you have about this now, with this
new information.
>ExecuteD.exe!OSMonitor::~OSMonitor() Line 35 C++
ExecuteD.exe!`OSMonitor::GetInstance'::`2'::`dynam ic atexit
destructor for 'instance''() + 0xd bytes C++
msvcr80d.dll!doexit(int code=0, int quick=0, int retcaller=1) Line
553 C
msvcr80d.dll!_cexit() Line 413 + 0xb bytes C
[External Code]
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::_Unin itializeDefaultDomain(void*
cookie = <undefined value>) Line 713 C++
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::Unini tializeDefaultDomain()
Line 729 + 0x8 bytes C++
ConsoleServer_d.dll!
<CrtImplementationDetails>::LanguageSupport::Domai nUnload(System::Object^
source = 0x048ef89c, System::EventArgs^ arguments = <undefined value>)
Line 762 C++
msvcm80d.dll!
<CrtImplementationDetails>::ModuleUninitializer::S ingletonDomainUnload(System::Object^
source = 0x048ef8bc, System::EventArgs^ arguments = <undefined value>)
Line 303 + 0x57 bytes C++
[Frames below may be incorrect and/or missing, no symbols loaded for
mscorwks.dll]
ntdll.dll!7c90e57c()
kernel32.dll!7c80a027()
kernel32.dll!7c80b683()

>ExecuteD.exe!OSMonitor::~OSMonitor() Line 35 C++
ExecuteD.exe!`OSMonitor::GetInstance'::`2'::`dynam ic atexit
destructor for 'instance''() + 0xd bytes C++
msvcr80d.dll!doexit(int code=0, int quick=0, int retcaller=1) Line
553 C
msvcr80d.dll!_cexit() Line 413 + 0xb bytes C
[External Code]
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::_Unin itializeDefaultDomain(void*
cookie = <undefined value>) Line 713 C++
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::Unini tializeDefaultDomain()
Line 729 + 0x8 bytes C++
ExecuteD.exe!
<CrtImplementationDetails>::LanguageSupport::Domai nUnload(System::Object^
source = 0x048ef89c, System::EventArgs^ arguments = <undefined value>)
Line 762 C++
msvcm80d.dll!
<CrtImplementationDetails>::ModuleUninitializer::S ingletonDomainUnload(System::Object^
source = 0x048ef8bc, System::EventArgs^ arguments = <undefined value>)
Line 303 + 0x57 bytes C++
[Frames below may be incorrect and/or missing, no symbols loaded for
mscorwks.dll]
ntdll.dll!7c90e57c()
kernel32.dll!7c80a027()
kernel32.dll!7c80b683()

Regards,
Josh
Jun 26 '07 #14

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@a26g2000pre.googlegr oups.com...
On Jun 22, 11:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>"Aek" <aek.muld...@gmail.comwrote in message

news:11*********************@i38g2000prf.googlegr oups.com...

I found something interesting today that I overlooked before.
The call stack of the atexit calls is showing _cexit calls coming from
different assemblies.
Sorry if this callstack cut and paste comes out a garbled mess in your
reader.. it basically shows that
ConsoleServer_d.dll is calling msvcr80d.dll!_cexit(), which cleans up
the local static... then
ExecuteD.exe calls msvcr80d.dll!_cexit() which again tries to clean up
the local static.

Interesting. ExecuteD.exe is what is run and consoleserver_d.dll is a
dll that it uses. At least now I have somewhere to focus my attention.
You are linking both with /MDd, right?

Jun 26 '07 #15

P: n/a
Aek
On Jun 26, 8:36 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
You are linking both with /MDd, right?
Yeah they are both /MDd

Josh

Jun 26 '07 #16

P: n/a
Aek
On Jun 26, 10:55 am, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 8:36 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
You are linking both with /MDd, right?

Yeah they are both /MDd

Josh
We came to a resolution on this issue. We found that once the
offending C++ DLL that used managed extensions was removed from the
main application, then the problem went away.
Luckily the managed dll didnt do that much, and was mostly prototype
code for a legacy task, so removing it was the best option. We have
other managed dlls that we continue to use, but there was something
specific about how this one was built or used that caused the problem.

We still have not found the root cause of the issue. There is likely
someway that we are building/configuring or using this managed C++ dll
that is causing it to automatically cleanup native types registered
with atexit in a different assembly.

Why the dll calls the CRT cleanup code and the fact that the main
executable does it again is odd, considering that there are a number
of checks in place around that automatic cleanup code to avoid this
problem.

I will spend a few hours today trying to create a small reproducible
case and if the root cause is not clear, perhaps I can post it here
for examination.

Thanks for all your help.
Regards,
Josh Stewart

Jun 27 '07 #17

P: n/a
Aek
On Jun 27, 1:14 pm, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 10:55 am, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 8:36 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
You are linking both with /MDd, right?
Yeah they are both /MDd
Josh

We came to a resolution on this issue. We found that once the
offending C++ DLL that used managed extensions was removed from the
main application, then the problem went away.
Luckily the managed dll didnt do that much, and was mostly prototype
code for a legacy task, so removing it was the best option. We have
other managed dlls that we continue to use, but there was something
specific about how this one was built or used that caused the problem.

We still have not found the root cause of the issue. There is likely
someway that we are building/configuring or using this managed C++ dll
that is causing it to automatically cleanup native types registered
with atexit in a different assembly.

Why the dll calls the CRT cleanup code and the fact that the main
executable does it again is odd, considering that there are a number
of checks in place around that automatic cleanup code to avoid this
problem.

I will spend a few hours today trying to create a small reproducible
case and if the root cause is not clear, perhaps I can post it here
for examination.

Thanks for all your help.
Regards,
Josh Stewart
For anyone that is interested in have a look at a small example of the
problem.. I have created a small reproducible example.
The offending DLL has had all of its managed code removed, so I do not
think it is the managed extensions C++ that was causing the problems
with that DLL.
The issue seems to be related to mixing a /clr built executable + dll
with a native C++ (no clr) library.

You can breakpoint in the destructor of the meyer singleton in the
native C++ lib to see it destroy twice.

Here is the example solution:
http://aek.bur.st/work/Example_AtExit_Issue.zip

If anyone has an idea about what the issue here is, please let me
know :)
Cheers,
Josh Stewart

Jun 28 '07 #18

P: n/a
Aek
On Jun 28, 8:20 pm, Aek <aek.muld...@gmail.comwrote:
On Jun 27, 1:14 pm, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 10:55 am, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 8:36 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
You are linking both with /MDd, right?
Yeah they are both /MDd
Josh
We came to a resolution on this issue. We found that once the
offending C++ DLL that used managed extensions was removed from the
main application, then the problem went away.
Luckily the managed dll didnt do that much, and was mostly prototype
code for a legacy task, so removing it was the best option. We have
other managed dlls that we continue to use, but there was something
specific about how this one was built or used that caused the problem.
We still have not found the root cause of the issue. There is likely
someway that we are building/configuring or using this managed C++ dll
that is causing it to automatically cleanup native types registered
with atexit in a different assembly.
Why the dll calls the CRT cleanup code and the fact that the main
executable does it again is odd, considering that there are a number
of checks in place around that automatic cleanup code to avoid this
problem.
I will spend a few hours today trying to create a small reproducible
case and if the root cause is not clear, perhaps I can post it here
for examination.
Thanks for all your help.
Regards,
Josh Stewart

For anyone that is interested in have a look at a small example of the
problem.. I have created a small reproducible example.
The offending DLL has had all of its managed code removed, so I do not
think it is the managed extensions C++ that was causing the problems
with that DLL.
The issue seems to be related to mixing a /clr built executable + dll
with a native C++ (no clr) library.

You can breakpoint in the destructor of the meyer singleton in the
native C++ lib to see it destroy twice.

Here is the example solution:http://aek.bur.st/work/Example_AtExit_Issue.zip

If anyone has an idea about what the issue here is, please let me
know :)
Cheers,
Josh Stewart
Someone at work found the solution..

In the managed DLL project, remove /NOENTRY from Linker -Command
Line -Additional Options
Note that this is the same as setting "No Entry Point" to "yes" in
Linker -Advanced.

Seems that the /NOENTRY was left in after converting from 2003 to 2005
project and should not be used in this case.

Still not sure why this affects the local statics in the native
library though.

Cheers,
Josh

Jul 2 '07 #19

P: n/a

"Aek" <ae*********@gmail.comwrote in message
news:11**********************@z28g2000prd.googlegr oups.com...
On Jun 28, 8:20 pm, Aek <aek.muld...@gmail.comwrote:
>On Jun 27, 1:14 pm, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 10:55 am, Aek <aek.muld...@gmail.comwrote:
On Jun 26, 8:36 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
You are linking both with /MDd, right?
Yeah they are both /MDd
Josh
We came to a resolution on this issue. We found that once the
offending C++ DLL that used managed extensions was removed from the
main application, then the problem went away.
Luckily the managed dll didnt do that much, and was mostly prototype
code for a legacy task, so removing it was the best option. We have
other managed dlls that we continue to use, but there was something
specific about how this one was built or used that caused the problem.
We still have not found the root cause of the issue. There is likely
someway that we are building/configuring or using this managed C++ dll
that is causing it to automatically cleanup native types registered
with atexit in a different assembly.
Why the dll calls the CRT cleanup code and the fact that the main
executable does it again is odd, considering that there are a number
of checks in place around that automatic cleanup code to avoid this
problem.
I will spend a few hours today trying to create a small reproducible
case and if the root cause is not clear, perhaps I can post it here
for examination.
Thanks for all your help.
Regards,
Josh Stewart

For anyone that is interested in have a look at a small example of the
problem.. I have created a small reproducible example.
The offending DLL has had all of its managed code removed, so I do not
think it is the managed extensions C++ that was causing the problems
with that DLL.
The issue seems to be related to mixing a /clr built executable + dll
with a native C++ (no clr) library.

You can breakpoint in the destructor of the meyer singleton in the
native C++ lib to see it destroy twice.

Here is the example
solution:http://aek.bur.st/work/Example_AtExit_Issue.zip

If anyone has an idea about what the issue here is, please let me
know :)
Cheers,
Josh Stewart

Someone at work found the solution..

In the managed DLL project, remove /NOENTRY from Linker -Command
Line -Additional Options
Note that this is the same as setting "No Entry Point" to "yes" in
Linker -Advanced.

Seems that the /NOENTRY was left in after converting from 2003 to 2005
project and should not be used in this case.

Still not sure why this affects the local statics in the native
library though.
The CRT entry-point sets up the various arrays and linked lists that handle
destruction of statics and globals for the module. If it wasn't called,
those lists wouldn't be set up correctly, and apparently the ones from the
main application were used instead. So all the statics were cleaned up,
instead of just the ones for the local module. Or something like that.
>
Cheers,
Josh

Jul 2 '07 #20

P: n/a
Aek
On Jul 2, 9:10 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
The CRT entry-point sets up the various arrays and linked lists that handle
destruction of statics and globals for the module. If it wasn't called,
those lists wouldn't be set up correctly, and apparently the ones from the
main application were used instead. So all the statics were cleaned up,
instead of just the ones for the local module. Or something like that.
Yeah in VS2003 I think we were manually initializing the CRT by
calling the functions in "_vcclrit.h" such as __crt_dll_initialize()
and using the /NOENTRY. But in VS2005 this is not required. I think it
was either a result of a automatic conversion of that project that
wasnt checked, or a conversion that was checked plus a bad merge.
It was hard to spot because the /NOENTRY was sitting in the Linker ->
Command Line -Additional Options (where we rarely have anything
specified)

Cheers,

-Josh

Jul 4 '07 #21

This discussion thread is closed

Replies have been disabled for this discussion.