-2

I have written the following code using the POSIX pthread library:

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

void *thread_function(void *arg) {
    char *code = "1";
}

int main() {
int res;
pthread_t a_thread;
void *thread_result;

res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
    perror("Thread creation failed");
    exit(EXIT_FAILURE);
}

sleep(5);
printf("\nWaiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result);
printf("res[%d]\n",res);
if (res != 0) {
    perror("Thread join failed");
    exit(EXIT_FAILURE);
}
res = pthread_join(a_thread, &thread_result);
printf("res[%d]\n",res);
exit(EXIT_SUCCESS);
}

On executing the code I got the following output:

Waiting for thread to finish...
res[0]
Segmentation fault (core dumped)

In the code, I want to test What happens if you call the pthread_jion() function twice after the thread is finished. The first call to the function is correct, and the second crash. The backtrace:

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  pthread_join (threadid=140150565050112, thread_return=0x7fffa0a2c508) at 
pthread_join.c:47
47    if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
Python Exception exceptions.ImportError No module named gdb.frames: 
#0  pthread_join (threadid=140150565050112, thread_return=0x7fffa0a2c508) at 
pthread_join.c:47
#1  0x00000000004008d5 in main ()

And I check the pthread_join.c file:

39 int
40 pthread_join (threadid, thread_return)
41      pthread_t threadid;
42      void **thread_return;
43 {
44   struct pthread *pd = (struct pthread *) threadid;
45 
46   /* Make sure the descriptor is valid.  */
47   if (INVALID_NOT_TERMINATED_TD_P (pd))
48     /* Not a valid thread handle.  */
49     return ESRCH;

In the line 47, the Macro definition checks Whether the pd is a valid thread handle. If not, return ESRCH(3).

However when I run the same code in another Linux environment, I got the following output:

Waiting for thread to finish...
res[0]
res[3]

Does it have anything to do with the environment? The two linux systems have same ldd version:

ldd (GNU libc) 2.17

same GLIBC:

GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBC_2.3
GLIBC_2.2.5
GLIBC_2.14
GLIBC_2.17
GLIBC_2.3.2
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGT

and the same linux kernel version:

Red Hat Enterprise Linux Server release 6.6 (Santiago)
PJ.Jing
  • 11
  • 3

1 Answers1

2

pthread_join calls pthread_detach after the thread has terminated. pthread_detach releases all the threads resources when the thread terminates.

From the documentation of pthread_detach

Attempting to detach an already detached thread results in unspecified behavior.

So you have unspecified behaviour, so you can't guarantee what will happen afterwards.

At the very least, the memory pointed to by the threadid will be freed, leading to accessing freed memory.

In short, don't call pthread_join twice on the same threadid. Why would you want to?

Edit: even simpler: the man page for pthread_join says:

Joining with a thread that has previously been joined results in undefined behavior.

The Dark
  • 8,453
  • 1
  • 16
  • 19