This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Distributions still suffering from s390 ABI change problems.


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);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]