Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87h79s2abh.fsf@oldenburg.str.redhat.com>
Date: Mon, 24 Jan 2022 20:38:42 +0100
From: Florian Weimer <fweimer@...hat.com>
To: Keith Packard <keithp@...thp.com>
Cc: Sebastian Huber <sebastian.huber@...edded-brains.de>,
  libc-coord@...ts.openwall.com
Subject: Re: Constructors/destructors for thread-local objects?

* Keith Packard:

> Sebastian Huber <sebastian.huber@...edded-brains.de> writes:
>
>> I have to admit that I didn't thought about dlopen(). You have to clear 
>> .tbss and initialize .tdata for existing threads, so there must be some 
>> way to get access to all existing threads. Wouldn't it be possible to 
>> run the thread-local constructors in a signal handler?
>
> Probably not a good plan — most of the Posix API isn't usable from
> signal handlers (including malloc).
>
> *maybe* we could call this in the syscall return path of the target
> thread? Even then I worry about semantics of any mutexes or other
> consequences of running code from an unknown context.

That system call could happen from an asynchronous signal, so we'd have
the same issue.  In glibc, we currently mark most wrappers as not
interfering with application code (that is, as leaf functions), and
running arbitrary callbacks from them would not be compatible with that,
even without symbols.

>> Yes, the resource allocation issue with __cxa_thread_atexit() was one of 
>> the reasons that let me think about the new sections. I would like to 
>> support applications which do not dynamically allocate memory at all.
>
> Hrm. The more I think about this, the more I suspect the best we can do
> is initialize the memory to values defined in the DLL and let the
> library deal with more complex initialization once it gets invoked and
> is running in a known state.

Yes, that's what I concluded as well.

>>> The destructors should probably take an iteration count as argument, and
>>> a return value that's non-zero if any action was taken by the
>>> destructor.  I think this is needed because it is not always possible to
>>> destruct per-thread resources in a single pass.  For example, a logger
>>> handle could be brought back to life if another destructor needs to log
>>> something.  The C library would keep running all destructors until all
>>> of them signal that no work was left to do anymore.
>
> I can't imagine a context in which it would be safe to run these
> destructors though, unless you want to allow them to be run from another
> thread.

Why?  They wouldn't be different from destructors registred using
pthread_key_create.

Dealing with dlclose is another matter, of course.  We could say that
once the classic ELF destructor for an object has started executing, the
new TLS destructors will no longer run for this object.  That should
cover most memory deallocation needs.  The classic ELF destructor would
need an application-specific way to enumerate allocated per-thread
resources.

Thanks,
Florian

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.