Date: Sat, 25 Feb 2012 01:56:13 -0500 From: Rich Felker <dalias@...ifal.cx> To: musl@...ts.openwall.com Subject: Re: tough choice on thread pointer initialization issue On Thu, Feb 09, 2012 at 09:58:25PM -0500, Rich Felker wrote: > the bug i've found occurs when the thread pointer happens to get > initialized in code that runs from a signal handler. this is a rare > situation that will only happen if the program is avoiding > async-signal-unsafe functions in the main flow of execution so that > it's free to use them in a signal handler, but despite being rare, > it's perfectly legal, and right now musl crashes on such programs, for > example: > [...] > the issue is that when a signal handler returns, all registers, > including the thread-pointer registers (%gs or %fs on x86 or x86_64) > are reset to the values they had in the code the signal interrupted. > thus, musl thinks the thread pointer is valid at this point, but it's > actually null. > [...] > before i make a decision, i'd like to hear if anyone from the > community has strong opinions one way or the other. i've almost ruled > out approach #1 and i'm leaning towards #3, with the idea that > simplicity is worth more than a couple trivial syscalls. PING. Any more thoughts on this issue? I've looked into the "solution 4" that Solar proposed, which simply put is making __pthread_self() check for a clobbered thread register and restore it. While this sounds simple, there are a few issues I've run into whereby it starts to get ugly... 1. The proper value of the %gs register (for i386) or %fs register (for x86_64) needs to be saved somewhere global so that __pthread_self can restore it. This seems to be solvable but requires putting a global 16-bit var in __set_thread_area.s and getting the asm right to make it PIC-safe, and might call for some extra weak symbol hackery to avoid pulling in excess code. 2. On x86_64, it seems that 0 is a valid value for %fs, so we can't really tell if it's uninitialized! I don't have a machine to test with, but from reading the kernel sources, it looks like %fs is 0 and a hidden 64-bit offset is stored in a privileged register accessible only by the kernel (one which hopefully would not be clobbered by sigreturn, but I'm not sure...) when the thread pointer does not fit in 32 bits, and the old i386 method (LDT entry and non-zero %fs selector value) is used when the thread pointer fits in 32 bits. This might be a show-stopper, because if we can't tell if the thread pointer is valid, we can't restore it (and the value of %fs might actually need to differ per-thread if some threads are below the 4gb boundary and others are located above). 3. The code in __pthread_self() to test %gs and call out to external code when it needs to be restored is larger than I would like, especially since the inline asm block uses no clobbers, thus requiring all registers to be saved across a call from the asm. With these issues in mind, Solar's solution is seeming less appealing and maybe not even feasible. Any ideas for salvaging it, or should I fall back to one of the other options? (My original leaning was towards always setting up the thread pointer prior to program entry.) Rich
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.