This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug nptl/11670] New: Variables defined in pthread_cleanup_push() macro may be optimised away which breaks __sigsetjmp
- From: "ceggers at gmx dot de" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sources dot redhat dot com
- Date: 5 Jun 2010 07:18:39 -0000
- Subject: [Bug nptl/11670] New: Variables defined in pthread_cleanup_push() macro may be optimised away which breaks __sigsetjmp
- Reply-to: sourceware-bugzilla at sourceware dot org
Please consider the following code snippset:
--- snipp ---
my_ptr = malloc(100);
pthread_cleanup_push(my_handler, my_ptr);
...
pthread_cleanup_pop(1);
--- /snipp ---
With -Os optimisation, the C equivalent of the optimised code can look similar
to this (pure C, __EXCEPTIONS not defined):
--- snipp ---
/* # define pthread_cleanup_push(routine, arg) */
do {
__pthread_unwind_buf_t __cancel_buf;
[OPTIMISED AWAY]void (*__cancel_routine) (void *) = (routine);
void *__cancel_arg = (arg);
int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)
__cancel_buf.__cancel_jmp_buf, 0);
if (__builtin_expect (not_first_call, 0))
{
my_handler (__cancel_arg); [__cancel_routine has been replaced by a fixed
function call]
__pthread_unwind_next (&__cancel_buf);
/* NOTREACHED */
}
__pthread_register_cancel (&__cancel_buf);
do {
...
<User code>
[somewhere here the stack memory for __cancel_arg is "reused" by another
variable, because ...]
<User code>
...
/* # define pthread_cleanup_pop(execute) */
do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */
} while (0);
__pthread_unregister_cancel (&__cancel_buf);
if (execute)
my_handler (my_ptr); [... __cancel_arg has been merged with my_ptr]
} while (0)
--- /snipp ---
The compiler seems to recognize that the content of my_ptr and __cancel_arg is
always the same, so there's no need to keep both on the stack. __cancel_arg in
pthread_cleanup_pop() is replaced by my_ptr.
As long as no cancellation happens everything is fine. my_handler() is always
called with the correct argument. But in case of cancellation siglongjmp() may
be called from a position after the stack memory for __cancel_arg has been
"reused". In this case __sigsetjmp() returns and my_handler() is called with
something different than the original value of my_ptr.
The problem is not limited to __cancel_arg, the same could also happen to
__cancel_buf or __cancel_routine (if not replaced by a fixed function call). I
think there's no guarantee that none of the three stack variables is discarded
between __pthread_register_cancel() and __pthread_unregister_cancel().
As a first try to solve this I've modified the macros so that they are more
similar to the variant used when __EXCEPTIONS is defined (using the __cleanup__
attribute from GCC). The result seems to work for me, but it's in the nature of
compiler optimisations that problems seems to be "disappeared" if something is
altered a little bit ...
--
Summary: Variables defined in pthread_cleanup_push() macro may be
optimised away which breaks __sigsetjmp
Product: glibc
Version: 2.12
Status: NEW
Severity: normal
Priority: P2
Component: nptl
AssignedTo: drepper at redhat dot com
ReportedBy: ceggers at gmx dot de
CC: glibc-bugs at sources dot redhat dot com
GCC build triplet: x86_64-unknown-linux-gnu
GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: arm-arm920t-linux-gnueabi
http://sourceware.org/bugzilla/show_bug.cgi?id=11670
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.