Home > Back-end >  Casting a struct to a void pointer and back again in a different thread changes member values
Casting a struct to a void pointer and back again in a different thread changes member values

Time:09-07

I am running some code using pthreads, and to pass information to the thread's function, I am using a struct. The struct (called struct tinfo) has two fields, one is a pointer to another struct and the other is an int, called socket. I am debugging using GDB, and prior to starting the new thread, the struct tinfo socket field has a value of 4. The thread function accepts a void * as its sole argument and the first thing it does it cast it to a struct tinfo *. Using GDB I am able to see that prior to this conversion, the value of the socket field is still 4. However, upon stepping to the next line, the value changes to 16. I figure this has something to do with the threads, but the 4 should be passed by value and nothing in the function that creates the threads modifies the struct tinfo after the thread is created, so I can't see why this would be the case. Below I've attached photos of GDB output, immediately after the thread starts, and then after stepping one line. Also, I will add the code from both the function that creates the threads and the actual thread function itself.

Immediately after entering the new thread
(also note that the debugging output prior to [New Thread 0x7ff...] is from the function that creates the threads) Immediately after entering the new thread

After stepping to the next line After stepping to the next line

Code from handle_connection (function that creates the threads):

enum tunmux_error handle_connection(struct tunmux *server, int client_socket) {
    struct tinfo info = { .server=server, .socket=client_socket };
    
    pthread_t thread_id;
    if (pthread_create(&thread_id, NULL, &thread_function, (void *)&info) != 0)
        return TM_ETHREAD;

    return pthread_detach(thread_id) ? TM_ETHREAD : TM_SUCCESS;
}

Code from thread_function (function that the threads run):

static void *thread_function(void *payload) {
    struct tinfo info = *(struct tinfo *)payload;
    struct tunmux server = *(info.server);
    int client_socket = info.socket;
    ...
}

CodePudding user response:

You're passing a pointer to a local variable pthread_create, then you immediately return from the function that created the thread. So by the time the thread attempts to read the pointed-to data, its lifetime has ended. Dereferencing a pointer to an object whose lifetime has ended triggers undefined behavior.

You need to dynamically allocate memory that you pass the the thread function:

enum tunmux_error handle_connection(struct tunmux *server, int client_socket) {
    struct tinfo *info = malloc(sizeof *info);
    info->server=server;
    info->socket=client_socket;
    
    pthread_t thread_id;
    if (pthread_create(&thread_id, NULL, &thread_function, info) != 0)
        return TM_ETHREAD;

    return pthread_detach(thread_id) ? TM_ETHREAD : TM_SUCCESS;
}

Then in your thread function, be sure to free the allocated memory when you're done with it.

static void *thread_function(void *payload) {
    struct tinfo info = *(struct tinfo *)payload;
    free(payload);
    ...
}
  • Related