Victor
Victor

Reputation: 385

C function change value on return. Corrupted stack?

I ran into a very weird problem today. Long story short, my function returns one value, the caller gets a different value. Somewhere around my code I have a call to:

Message* m = NULL;
m = connection_receive(c);

Where connection_receive is defined as follows:

Message* connection_receive(Connection* c)
{
Message* k;

    if (c->state == CON_STATE_AUTHENTICATED)
    {
        pthread_mutex_lock(&c->mutex_in);

        if (g_queue_is_empty(c->in))
            k = NULL;
        else
            k = (Message*)g_queue_pop_head(c->in);

        pthread_mutex_unlock(&c->mutex_in);
        /* Until here, k is reachable and contains the correct data. */
        return k;
    }
    else
        return NULL; 
}

Here's a gdb run, I stopped right before the return and right after the assignment:

222         return k;
(gdb) p k
$1 = (Message *) 0x7ffff0000950
(gdb) n
226 }
(gdb) n
main () at src/main.c:57
57              if (m)
(gdb) p m
$2 = (Message *) 0xfffffffff0000950

Of course, if we try to access 0xfffffffff0000950 we'll get a segmentation fault.

If I change the function and instead of returning a value, using a second parameter to pass the value it works, but I would like to know what went wrong on this one.

Thank you very much.

EDIT: This works, but it's not convenient. And I would also like to know why such strange error is happening.

void connection_receive2(Connection* c, Message** m)
{
    if (c->state == CON_STATE_AUTHENTICATED)
    {
        pthread_mutex_lock(&c->mutex_in);

        if (g_queue_is_empty(c->in))
            *m = NULL;
        else
            *m = (Message*)g_queue_pop_head(c->in);

        pthread_mutex_unlock(&c->mutex_in);
    }
    else
        *m = NULL;
}

EDIT2: Solved. Thanks all. The problem was a typo on the header file. I can't use -Werror because I need to do things which raise some warnings, and in a large make output and large header I missed it.

Upvotes: 8

Views: 2713

Answers (3)

walter
walter

Reputation: 1

We faced the same problem and the root cause was the implicit declaration of the function connection_receive(). So it was defaulted to int which signed and then stored in m.

Upvotes: 0

AndersK
AndersK

Reputation: 36102

Did you push a malloc:ed object on the queue? If not and you instead pushed a stack object then when you may end up with weird behavior when you pop items.

Upvotes: 0

glglgl
glglgl

Reputation: 91099

  1. How is your m defined?
  2. Has your caller access to the right prototype?
  3. What architecture are you on?

I suspect that there is a mismatch with the types and that my question 2 is the crux of all.

You are returning a pointer with (I suppose so) 48 or 64 bits. The caller, however, thinks to get a int, which has maybe 32 bits and is signed. On converting back to a pointer, the value gets sign-extended.

Upvotes: 6

Related Questions