Problem with locales in unloaded DLLs

H

Hendrik Schober

[x-posted to microsoft.public.dotnet.languages.vc
and microsoft.public.vc.stl]

Hi,

we just ran into a bug that seems to be a show-
stopper for us.
We are making a plugin (DLL) for some application.
It is loaded from the app (presumably) using
'LoadLibrary()'. Then code in the DLL is executed.
Sometimes, this implies calls to 'std::issspace()'
which in turn will call 'locale::facet::_Register()'
to register a locale with the C++ runtime. Later
on, the DLL will be unloaded. However, the run-
time only treis to un-register the facet when the
/process/ terminates. At this time the DLL is long
gone and the app thus crashes at shutdown.

A search across the KB (using the term "register
locale crash") didn't come up with something.
Google did find a reference to what appears to be
this bug. (Search for the string "DINKUMWARE BUG"
on http://cvs.sourceforge.net/viewcvs.py/filezilla/FileZilla Server/source/misc/StdString.h?rev=1.4)

Is there any fix for this? We use a few 3rd-party
libs that call locale-dependend functions which
will trigger this bug. It would be a huge problem
if we had to go through all this code and try to
understand it in order to fix the problem.

TIA,

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 
D

Doug Harrison [MVP]

Hendrik said:
[x-posted to microsoft.public.dotnet.languages.vc
and microsoft.public.vc.stl]

Hi,

we just ran into a bug that seems to be a show-
stopper for us.
We are making a plugin (DLL) for some application.
It is loaded from the app (presumably) using
'LoadLibrary()'. Then code in the DLL is executed.
Sometimes, this implies calls to 'std::issspace()'
which in turn will call 'locale::facet::_Register()'
to register a locale with the C++ runtime. Later
on, the DLL will be unloaded. However, the run-
time only treis to un-register the facet when the
/process/ terminates. At this time the DLL is long
gone and the app thus crashes at shutdown.

A search across the KB (using the term "register
locale crash") didn't come up with something.
Google did find a reference to what appears to be
this bug. (Search for the string "DINKUMWARE BUG"
on http://cvs.sourceforge.net/viewcvs.py/filezilla/FileZilla Server/source/misc/StdString.h?rev=1.4)

Is there any fix for this? We use a few 3rd-party
libs that call locale-dependend functions which
will trigger this bug. It would be a huge problem
if we had to go through all this code and try to
understand it in order to fix the problem.

Can't you solve this problem by statically linking to the C and C++
runtimes? I think that's a very appropriate thing to do for plug-in DLLs, or
in general, DLLs that can be loaded into unknown environments, such as
Windows global hook DLLs, DLLs that implement coclasses, etc.
 
H

Hendrik Schober

Doug Harrison said:
[...]

Can't you solve this problem by statically linking to the C and C++
runtimes? I think that's a very appropriate thing to do for plug-in DLLs, or
in general, DLLs that can be loaded into unknown environments, such as
Windows global hook DLLs, DLLs that implement coclasses, etc.

I wouldn't have thought this could fix the
problem. I can try this tomorrow when I'm
back at work.
But isn't this the same then? The DLL is
loaded, the RTL gets initialized, the code
runs, and at the end, the DLL is unloaded,
for which the RTL needs to do the cleanup.
If the RTL stores some pointer somewhere
to an object that's to be deleted, and it
will try to delete it at process' end, then
the DLL (and the object) will be gone.
Or am I missing something?

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 
I

Igor Tandetnik

Hendrik Schober said:
Doug Harrison said:
[...]

Can't you solve this problem by statically linking to the C and C++
runtimes? I think that's a very appropriate thing to do for plug-in
DLLs, or in general, DLLs that can be loaded into unknown
environments, such as Windows global hook DLLs, DLLs that implement
coclasses, etc.

I wouldn't have thought this could fix the
problem. I can try this tomorrow when I'm
back at work.
But isn't this the same then? The DLL is
loaded, the RTL gets initialized, the code
runs, and at the end, the DLL is unloaded,
for which the RTL needs to do the cleanup.

When linked statically, the DLL has its own copy of CRT, which performs
its own initialization and clean-up independently of the EXE. This
private copy initializes when the DLL loads, and cleans up when the DLL
unloads.
--
With best wishes,
Igor Tandetnik

"On two occasions, I have been asked [by members of Parliament], 'Pray,
Mr. Babbage, if you put into the machine wrong figures, will the right
answers come out?' I am not able to rightly apprehend the kind of
confusion of ideas that could provoke such a question." -- Charles
Babbage
 
H

Hendrik Schober

Igor Tandetnik said:
[...]

When linked statically, the DLL has its own copy of CRT, which performs
its own initialization and clean-up independently of the EXE. This
private copy initializes when the DLL loads, and cleans up when the DLL
unloads.

I see. Thanks for the clarification.
Meanwhile I have checked with the company
that makes the application we're doing
the plugin for. They agreed that this bug
was introduced by dynamically linking to
the RTL.
However, they also say that dynamically
linking to the RTL speeds up the startup
considerably. (There are many plugins.)
So I am asked to keep the dynamic linking
and fix the problem anyway. <sigh>

Isn't there a fix for this??? This bug
effectively prevents DLLs from dynamically
linking to the RTL! This surely must have
affected /many/ users.

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 
V

Vladimir Nesterovsky

One way to fix this is not to unload DLL. Just add one uncompensated
LoadLibrary call into your code.
This isn't so terrible as it seems.
 
H

Hendrik Schober

Vladimir Nesterovsky said:
One way to fix this is not to unload DLL. Just add one uncompensated
LoadLibrary call into your code.
This isn't so terrible as it seems.

The problem is, this isn't our code.
We don't even get to see the source.
All we have is a plugin API and a
binary.


Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 
V

Vladimir Nesterovsky

The problem is, this isn't our code.
We don't even get to see the source.
All we have is a plugin API and a
binary.

You can call LoadLibrary from within your code. But be sure not to invoke
LoadLibrary from the DllMain.

// YourClass is never instantiated in the DllMain.
class YourClass
{
private:
static bool Initialize()
{
return LoadLibrary("your library") != 0;
}
public:
YourClass()
{
static bool initialized = Initialize();

...
}
};
 
D

Doug Harrison [MVP]

Vladimir said:
You can call LoadLibrary from within your code. But be sure not to invoke
LoadLibrary from the DllMain.

// YourClass is never instantiated in the DllMain.
class YourClass
{
private:
static bool Initialize()
{
return LoadLibrary("your library") != 0;
}
public:
YourClass()
{
static bool initialized = Initialize();

...
}
};

And remember that DLL globals are initialized by DllMain, so you mustn't
have a DLL global YourClass, or a DLL global which uses YourClass. Also,
it's worth mentioning that local statics in DLLs typically aren't destroyed
in accordance with the standard's LIFO policy; much more on that here:

http://groups.google.com/[email protected]

To summarize the warning in that message, if you have a DLL local static
that is only ever initialized by the EXE, the destructor for that object
will be run in DllMain context and must obey the DllMain restrictions.
 
D

Doug Harrison [MVP]

Hendrik said:
But isn't this the same then? The DLL is
loaded, the RTL gets initialized, the code
runs, and at the end, the DLL is unloaded,
for which the RTL needs to do the cleanup.
If the RTL stores some pointer somewhere
to an object that's to be deleted, and it
will try to delete it at process' end, then
the DLL (and the object) will be gone.
Or am I missing something?

That's an interesting question. Let's assume that when it's shutting down,
the RTL will execute a dtor residing in a DLL that was never unloaded but
has already been uninitialized. Further, we'll assume both EXE and DLL link
to the same CRT, so there's only one heap. IOW, we have an app that
implicitly links to DLLs that become tightly integrated into it.

I don't think there are any data issues distinct from the case of an
application that uses static linking throughout. So, is the DLL dtor code
still mapped into the process? I've looked into this before but never found
a concrete answer. Empirically speaking, I'd bet yes, but it does seem like
it would be in a weird state of limbo, executing after the DLL received its
DLL_PROCESS_DETACH notification.
 
H

Hendrik Schober

Doug Harrison said:
That's an interesting question. Let's assume that when it's shutting down,
the RTL will execute a dtor residing in a DLL that was never unloaded but
has already been uninitialized. Further, we'll assume both EXE and DLL link
to the same CRT, so there's only one heap. IOW, we have an app that
implicitly links to DLLs that become tightly integrated into it.

I don't think there are any data issues distinct from the case of an
application that uses static linking throughout. So, is the DLL dtor code
still mapped into the process? I've looked into this before but never found
a concrete answer. Empirically speaking, I'd bet yes, but it does seem like
it would be in a weird state of limbo, executing after the DLL received its
DLL_PROCESS_DETACH notification.


IIUC, the issue is a stored vptr referencing
a vtable in the already unloaded DLL.
As I had to find out last night <yawn>, the
problem isn't easily reproducable. I am still
not sure about what is necessary.

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top