On Apr  9 23:32, Jeremy Drake via Cygwin wrote:
> On Wed, 9 Apr 2025, Jeremy Drake via Cygwin wrote:
> 
> > On Thu, 10 Apr 2025, Kevin Schnitzius via Cygwin wrote:
> >
> > > On Wednesday, April 9, 2025 at 06:54:34 PM EDT, Jeremy Drake via Cygwin 
> > > <cygwin@cygwin.com> wrote:
> > >
> > > > The recent issue with pthread_atfork handlers reminded me of a scenario
> > > > that I know glibc handles, but it seems that Cygwin does not.  Test 
> > > > case:
> > >
> > > <... code that loads a shared lib, registers some functions in shared lib 
> > > with pthread_atfork(), unloads the shared lib, and crashes on fork...>
> > >
> > > Calling functions in an unloaded library should result in undefined 
> > > behavior.
> > >
> > > However, further investigation reveals that the Linux pthread_atfork() 
> > > registered functions are not being called and POSIX does not proved a 
> > > mechanism for un-registering these functions.   Note: pthread_atfork() is 
> > > not bumping the ref count on the shared lib--those functions are 
> > > definitely unavailable after the dlclose()
> > >
> > > In the Cygwin version, calling the functions in the unloaded library when 
> > > the fork happens causes the crash.
> > >
> > > This seems to be a bug with fork(), if it is a bug at all.
> >
> > I did a quick search, and found a write-up of *my* bug report :D
> >
> > https://developers.redhat.com/articles/2022/12/14/how-we-addressed-unforeseen-use-case-pthreadatfork
> >
> > "Now, dlclose()'ing a module means that any fork handlers registered by it
> > should not be executed after the dlclose and should therefore implicitly
> > be deregistered."
> 
> It seems glibc takes care of this implicit deregistration in
> __cxa_finalize, after calling __cxa_atexit functions, it unregisters any
> at_quick_exit or pthread_atfork callbacks from the DSO being unloaded.
> 
> https://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/cxa_finalize.c;h=2bb35602edc6bf842e5d2c93ad03454d7b57ee65;hb=HEAD
> 
> It doesn't look like newlib deals with either at_quick_exit or
> pthread_atfork handlers in its __cxa_finalize implementation.

Cygwin is doing this stuff mostly in its own code, see thread.cc.
It keeps lists of the callbacks in a global structure which is
called MT_INTERFACE throughout thread.cc.

The functions pthread::atforkprepare(), pthread::atforkparent() and
pthread::atforkchild () are called from different spots during fork().

Here's what we're missing:

- Either keep track of the DLL a callback function is coming from by
  calling dlls.find (handle, true) and store the struct dll pointer.
  In dlclose(), if the DLL is of type DLL_LOAD or DLL_NATIVE, and
  the refcounter indicates that this is the last FreeLibrary, check the
  three callback lists in MT_INTERFACE and remove all functions
  with the same struct dll pointer.

- Or, instead of keeping track, tweak the aformentioned three functions
  to call GetModuleHandleEx() just as dladdr() does, and if it returns
  NULL, remove the callback from the list on the fly.


Corinna

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to