1

Can you explain why in Linux (not in Mac) I get Segmentation Fault when I do:

pthread_join(thread2, (void**)&status);
pthread_join(thread1, (void**)&status);

But is ok when I do:

pthread_join(thread1, (void**)&status);
pthread_join(thread2, (void**)&status);

I tried on Mac and everything is fine, but in Linux the code run properly only if I do the join of the thread1 and after that the join of thread2...

This is my code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_msg( char *ptr );

main(){
    pthread_t thread1, thread2;
    char *message1 = "Ping";
    char *message2 = "Pong";
    int status;
    pthread_create(&thread1, NULL, print_msg, message1);
    printf("tid thread1= %d\n", (int)thread1);
    pthread_create(&thread2, NULL, print_msg, message2);
    printf("tid thread2= %d\n", (int)thread2);
    pthread_join(thread2, (void**)&status);
    pthread_join(thread1, (void**)&status);
    printf("Thread 1 end with: %d\n", (int)status);
    printf("Thread 2 end with: %d\n", (int)status);
    exit(0);
}

void *print_msg( char *ptr ){
    char *msg;
    void *val=0;
    msg = (char *) ptr;
    printf("%s \n", msg);
    pthread_exit(val);
}
Giovanni
  • 79
  • 8
  • 3
    You may want to fix all the compiler warnings first, there are a few. You can compile your code with `-Wall` and `-Wextra` which tells you a lot of potential error. You can also read [pthread doc](http://man7.org/linux/man-pages/man3/pthread_create.3.html) which contains example on how to use `pthread_join()` – SSC Nov 12 '16 at 09:24

2 Answers2

0

Your cast of (void**)&status is the problem.

status is an integer with an uninitialized value in it. It's also not a pointer. sizeof(status) is likely 4. While sizeof(void*) is likely 8. So when pthread_join is invoked, it's going to trash 4 bytes of the stack past the stack location of status. That very well could be the return address of the main function. But at this point, we are in undefined behavior territory.

Change the declaration of status to be a void*. As you should with any pointer value, initialize it to NULL. That is:

void* status = NULL;

Then subsequently, simplify your pthread_join statements so you don't need the cast.

pthread_join(thread2, &status);
pthread_join(thread1, &status);
selbie
  • 100,020
  • 15
  • 103
  • 173
  • It'd be good to note that this is in correspondence with the type of a start routine for `pthread_create`: `void *(*start_routine) (void *)` – Michael Foukarakis Nov 25 '16 at 10:26
-1

I think I've figured it out.

The problem is that Linux doesn't have enough time to create all what it needs to manage the thread because we ask for the join immediatly. If we just insert even one stupid instruction between we solve the problem:

...
pthread_create(&thread1, NULL, print_msg, message1);
printf("tid thread1= %d\n", (int)thread1);
pthread_create(&thread2, NULL, print_msg, message2);
int a=0;
pthread_join(thread2, (void**)&status);
pthread_join(thread1, (void**)&status);
...
Giovanni
  • 79
  • 8
  • Also, the reason why the above seems to work is likely because your insertion of a new stack variable, `a`. Since it follows `status` in the declaration order, it likely is what's absorbing your buffer overrun. I wouldn't be surprised if the value of `a` has changed after the return from pthread_join. – selbie Nov 25 '16 at 18:50