This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Distributions still suffering from s390 ABI change problems.
- From: Aurelien Jarno <aurelien at aurel32 dot net>
- To: Carlos O'Donell <carlos at redhat dot com>
- Cc: David Miller <davem at davemloft dot net>, Andreas Krebbel <krebbel at linux dot vnet dot ibm dot com>, siddhesh at redhat dot com, allan at archlinux dot org, libc-alpha at sourceware dot org
- Date: Tue, 15 Jul 2014 13:14:55 +0200
- Subject: Re: Distributions still suffering from s390 ABI change problems.
- Authentication-results: sourceware.org; auth=none
- References: <20140713182420 dot GA14513 at hall dot aurel32 dot net> <20140714052022 dot GR609 at spoyarek dot pnq dot redhat dot com> <20140714072228 dot GF1239 at hall dot aurel32 dot net> <20140714 dot 002520 dot 985400136122770421 dot davem at davemloft dot net> <53C40A5A dot 5050202 at redhat dot com> <20140714183123 dot GH1239 at hall dot aurel32 dot net> <20140714221933 dot GJ1239 at hall dot aurel32 dot net> <53C4B152 dot 7090606 at redhat dot com> <20140715051806 dot GA32518 at hall dot aurel32 dot net>
On Tue, Jul 15, 2014 at 07:18:06AM +0200, Aurelien Jarno wrote:
> On Tue, Jul 15, 2014 at 12:42:58AM -0400, Carlos O'Donell wrote:
> > The problem is that pthread_cleanup_push and pthread_cleanup_pop,
> > to name two functions, are implemented as macros that embed the
> > size of the __pthread_unwind_buf_t into the calling program.
> >
> > It would seem to me that you are correct in that all programs that
> > call:
> > * pthread_cleanup_push
> > * pthread_cleanup_pop
> > * pthread_cleanup_push_defer_np
> > * pthread_cleanup_pop_restore_np
> >
> > Will contain a too-small __pthread_unwind_buf_t structure which
> > will get interpreted internally as a pthread_unwind_buf of the
> > newer ABI size and that will cause reads from beyond the size
> > of the structure which is undefined behaviour.
> >
> > Did I get that right?
>
> Yes, it's correct. In addition to reads beyond the size, it seems that
> some data end-up being corrupted, and the longjmp is done at the wrong
> address. I haven't fully understood the whole process yet.
Please find attached a small program to demonstrate the issue. It works
well when compiled and run with pre-2.19 libc, but ends up with a
segmentation fault when compiled with a pre-2.19 libc and run with a
2.19 libc:
| (gdb) run
| Starting program: /home/aurel32/libc-jmp/pthread_cleanup_push
| warning: Could not load shared library symbols for linux-vdso64.so.1.
| Do you need "set solib-search-path" or "set sysroot"?
| [Thread debugging using libthread_db enabled]
| Using host libthread_db library "/lib/s390x-linux-gnu/libthread_db.so.1".
| [New Thread 0x3fffddf8910 (LWP 26020)]
| New thread started
| Canceling thread
| Clean-up handler
| Clean-up handler
|
| Program received signal SIGSEGV, Segmentation fault.
| [Switching to Thread 0x3fffddf8910 (LWP 26020)]
| unwind_stop (version=<optimized out>, actions=<optimized out>, exc_class=<optimized out>, exc_obj=<optimized out>, context=0x3fffddf7a58, stop_parameter=0x0) at unwind.c:61
| 61 || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context,
| (gdb) bt full
| #0 unwind_stop (version=<optimized out>, actions=<optimized out>, exc_class=<optimized out>, exc_obj=<optimized out>, context=0x3fffddf7a58, stop_parameter=0x0) at unwind.c:61
| buf = 0x0
| self = 0x3fffddf8910
| curp = 0x0
| do_longjump = 0
| adj = 4398010830848
| #1 0x000003fffd5dfd98 in ?? () from /lib/s390x-linux-gnu/libgcc_s.so.1
| No symbol table info available.
| #2 0x000003fffd5e0192 in _Unwind_ForcedUnwind () from /lib/s390x-linux-gnu/libgcc_s.so.1
| No symbol table info available.
| #3 0x000003fffdfae1c6 in __GI___pthread_unwind (buf=<optimized out>) at unwind.c:129
| ibuf = <optimized out>
| self = <optimized out>
| #4 0x000003fffdfae1e6 in __GI___pthread_unwind_next (buf=<optimized out>) at unwind.c:173
| ibuf = <optimized out>
| #5 0x0000000080000bbe in thread_start (arg=<optimized out>) at pthread_cleanup_push.c:17
| __cancel_buf = {__cancel_jmp_buf = {{__cancel_jmp_buf = {{__gregs = {4398010829072, 4398012666640, 4398010827264, 4398046507584, 0, 4398010830120, 4398012665856, 4398012636648, 16908663340921544,
| 16907918394819800}, __fpregs = {0, 0, 0, 0, 0, 0, 0, 0}}}, __mask_was_saved = 0}}, __pad = {0x0, 0x0, 0x0, 0x1}}
| __not_first_call = <optimized out>
| #6 0x0000000000000000 in ?? ()
| No symbol table info available.
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
aurelien@aurel32.net http://www.aurel32.net
#include <pthread.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
static void cleanup_handler(void *arg)
{
printf("Clean-up handler\n");
}
static void *thread_start(void *arg)
{
printf("New thread started\n");
pthread_cleanup_push(cleanup_handler, NULL);
pthread_cleanup_push(cleanup_handler, NULL);
for (;;)
pthread_testcancel();
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thr;
int s;
void *res;
s = pthread_create(&thr, NULL, thread_start, NULL);
if (s != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
sleep(2);
printf("Canceling thread\n");
s = pthread_cancel(thr);
if (s != 0) {
perror("pthread_cancel");
exit(EXIT_FAILURE);
}
s = pthread_join(thr, &res);
if (s != 0) {
perror("pthread_join");
exit(EXIT_FAILURE);
}
if (res == PTHREAD_CANCELED)
printf("Thread was canceled\n");
else
printf("Thread terminated normally\n");
exit(EXIT_SUCCESS);
}