Wayne Hong
Wayne Hong

Reputation: 119

Struct argument passed in pthread create gets mangled

I have a structure named command that looks like this. The first value in the enum is AND_COMMAND

struct command
{
  enum command_type type;
  int status;
  char *input;
  char *output;
  union
  {
    struct command *command[2];
    char **word;
    struct command *subshell_command;
  } u;
};

When I call pthread_create I pass it a command in the form of a command_t (that is cast to (void *)).

typedef struct command *command_t;

My thread takes this (void *) command_t, casts it back (command_t) and tries to use the structure.

void execute_thread(void *c) {
  command_t command = (command_t) c;

However when I pass a struct in to execute_thread the first values are zeroed out. If I have a command_type of SIMPLE_COMMAND and status of -1, when it's passed in to the thread the command_type is AND_COMMAND and status of 0. None of the other values in the struct are changed however. What's more curious is when this data mangling occurs. I was able to capture the phenomenon in gdb:

445   command_t command = (command_t) c;
(gdb) p *((command_t) c)
$6 = {type = SIMPLE_COMMAND, status = -1, input = 0x605370 "abc", output = 0x605390 "def", u = {
command = {0x6052e0, 0x0}, word = 0x6052e0, subshell_command = 0x6052e0}}
(gdb) n
(gdb) p *((command_t) c)
$7 = {type = AND_COMMAND, status = 0, input = 0x605370 "abc", output = 0x605390 "def", u = {command = {
  0x6052e0, 0x0}, word = 0x6052e0, subshell_command = 0x6052e0}}

It appears that the structure pointed to by c doesn't change until casting it with (command_t) c; I am entirely confounded by this behavior. I didn't think that casting a pointer could change the values it pointed to. Could someone please point out, ha ha, what could be going on here? I would appreciate that very much.

Upvotes: 0

Views: 373

Answers (1)

Michael Burr
Michael Burr

Reputation: 340188

What's more curious is when this data mangling occurs. I was able to capture the phenomenon in gdb:

The wording here leads me to believe that the problem isn't deterministic; ie., sometimes it doesn't happen, or it doesn't happen at the moment you happened to capture in gdb in the question.

If that's the case (and maybe even if it isn't), I suspect that you problem is that you're trashing the memory allocated to the struct command in the main thread (or whatever thread is creating the execute_thread() thread). You didn't show us the thread creation code, but if you use a local variable and pass the address of that to the created thread, then it can be tricky to make sure the local variable's lifetime doesn't expire before the the second thread gets around to using it. You might want to pass in a struct command that has been allocated on the heap:

struct command* thread_data = malloc(sizeof(struct command));
struct_command_init(thread_data);

pthread_create(/* ... */, thread_data);
// ...

and in the execute_command() thread:

void* execute_command(void* p)
{
    struct command cmd = *(struct command*)p;
    free(p);

    // use cmd to get at the structure data passed in...
}

Keep in mind that the data referred to by various pointers insode the struct command also need to have their lifetime and ownership clearly managed, too.

Upvotes: 2

Related Questions