Address space clobbers during fork() (was Re: Extending /proc/*/maps)

Corinna Vinschen
Thu Apr 21 08:54:00 GMT 2011

On Apr 19 14:16, Ryan Johnson wrote:
> On 19/04/2011 12:01 PM, Corinna Vinschen wrote:
> >On Apr 19 11:38, Ryan Johnson wrote:
> >>BTW, /cygdrive/c/Windows/System32/locale.nls seems to be the reason
> >>that even statically linked dlls don't always load in the same place
> >>twice in a row.
> >How so?  And then, when is it loaded?  I assume that this file is
> >fetched as soon as the GetLocaleInfo function is called.  What OS
> >are you using?  If it's Vista or later, there's a chance that the
> >LocaleNameToLCID function is the culprit as well.  But the real
> >problem is, how can that be worked around?  For the locale stuff
> >we need these functions.
> (subject changed to reflect what we're actually discussing)
> I'm using Win7-x64.
> When locale.nls gets mapped in, Windows doesn't always put it in the
> same place. As a result, fork() can run into all the usual problems
> with DLL base addresses, except it can bite even statically-linked
> dlls.
> [...]
> Recall that cygfoo.dll and cygbar.dll both want to load at 00660000.
> The latter always gets the coveted base address because it always
> loads first (last in link order? luck?). In the parent, locale.nls
> maps to 002B0000, while cygfoo.dll loads at 00320000. The child, on
> the other hand, puts cygfoo.dll at 002B0000, and maps locale.nls to
> 00380000. That latter address is reserved for some sort of anonymous
> memory in the parent (most likely a thread stack,*** since there are
> some guarded pages at 003B9000 and it's not a heap). My best guess
> is that this stack lives at 00410000 in the child, which is free
> space in the parent.

Unfortunately there's no way set the thread stack address manually.
If we want to have that under control we would have to create a thread,
then create a new stack and free the original one.  That's kind of
tricky.  Or slow.

> The other main difference is the lack of shared memory in the child
> and completely different heaps. I assume the former is because
> cygwin hasn't finished initializing yet, and will not be a problem.
> I don't know whether the latter matters wrt fork() semantics, but it
> certainly is another potential source of address space clobbers.
> It's also rather odd that the child has 3-4 heaps when its parent
> has only 1-2.

Maybe that's some of the anti-hijacking measures in Windows.  ASLR?

> I actually hadn't noticed that thread stack before making the diff,
> so at this point it's a toss-up which of the thread or locale.nls
> got there first and messed up the other. Does Windows tend to map
> files at the same address every time, or just executable images it
> hopes to share as-is between processes? Without knowing that it's
> hard to say what happened.

I assume it will map the file to the same address if there's nothing
else already in the way.  This should make virtual memory handling
easier.  OTOH locale.nls is just a data file, so Win32 shouldn't care
at all where it's located.

> Regardless of file mapping behavior, though, I don't see right off
> how to make this problem go away.

Just an idea:  What if we map locale.nls to some fixed address ourselves
before any NLS function is called?  Somewhere early in dll_crt0_1.
If the file is already mapped, there should be no reason for the OS to
map it again at some other address.


Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

More information about the Cygwin-developers mailing list