pthread_cleanup_push error

Bug #575008 reported by petter wahlman
2
Affects Status Importance Assigned to Milestone
eglibc (Ubuntu)
Invalid
Undecided
petter wahlman

Bug Description

Code to trigger the problem:
================================================================
#include <stdio.h>
#include <pthread.h>

static void thread_destructor(void *arg)
{
    printf("die!\n");
}

int main(int argc, const char *argv[])
{
    pthread_cleanup_push(thread_destructor, NULL);

    return 0;
}

Compiling results in the following errors:
================================================================
/tmp/ cc foo.c -Wall
foo.c: In function ‘main’:
foo.c:14: error: expected ‘while’ at end of input
foo.c:14: error: expected declaration or statement at end of input
foo.c:14: error: expected declaration or statement at end of input

The problem is obvious if you look at the code generated by the preprocessor:
('do { } while(0)' is not terminated with '} while(0)', but 'do {' )
================================================================
...
int main(int argc, char **argv)
{
    do { __pthread_unwind_buf_t __cancel_buf; void (*__cancel_routine) (void *) = (((void *)0)); void *__cancel_arg = (((void *)0)); int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) __cancel_buf.__cancel_jmp_buf, 0); if (__builtin_expect (not_first_call, 0)) { __cancel_routine (__cancel_arg); __pthread_unwind_next (&__cancel_buf); } __pthread_register_cancel (&__cancel_buf); do {;

    return 0;
}

The correct code should look similar to the following:
================================================================
#define pthread_cleanup_push(__thread_destructor, __arg) \
do { \
    __pthread_unwind_buf_t __cancel_buf; \
    void (*__cancel_routine) (void *) = (__thread_destructor); \
    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)) { \
        __cancel_routine (__cancel_arg); \
        __pthread_unwind_next (&__cancel_buf); \
    } \
    __pthread_register_cancel (&__cancel_buf); \
} while(0)

ProblemType: Bug
DistroRelease: Ubuntu 10.04
Package: libc6-dev 2.11.1-0ubuntu7
ProcVersionSignature: Ubuntu 2.6.31-17.54-generic
Uname: Linux 2.6.31-17-generic x86_64
Architecture: amd64
Date: Tue May 4 09:57:52 2010
InstallationMedia: Ubuntu 9.10 "Karmic Koala" - Release amd64 (20091027)
ProcEnviron:
 PATH=(custom, user)
 LANG=en_US.utf8
 SHELL=/bin/bash
SourcePackage: eglibc

Revision history for this message
petter wahlman (petter-wahlman) wrote :
description: updated
summary: - the pthread_cleanup_push macro generates incorrect code
+ pthread_cleanup_push error
tags: removed: amd64 apport-bug lucid
Changed in eglibc (Ubuntu):
assignee: nobody → petter wahlman (petter-wahlman)
status: New → Invalid
Revision history for this message
Josh Matthews (joshmatthews-gmail) wrote :

Not a bug. A pthread_cleanup_push must be accompanied by a matching pthread_cleanup_pop. The macro definition contains an explanation:

/* Believe or not, the definitions of pthread_cleanup_push and
 * pthread_cleanup_pop below are correct. Posix states that these
 * can be implemented as macros that might introduce opening and
 * closing braces, and that using setjmp/longjmp/return/break/continue
 * between them results in undefined behaviour.
 *
 * And indeed, GLibc and other C libraries use a similar definition
 */
#define pthread_cleanup_push(routine, arg) \
    do { \
        __pthread_cleanup_t __cleanup; \
        __pthread_cleanup_push( &__cleanup, (routine), (arg) ); \

#define pthread_cleanup_pop(execute) \
        __pthread_cleanup_pop( &__cleanup, (execute)); \
    } while (0);

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.