free(src) after memcpy(dst, src, n) causes a segfault

时间:2015-07-28 16:33:41

标签: c segmentation-fault

Consider the code below:

int main(int argc, char* argv[])
{
    int prt = 6;
    serial_port *cprt = open_comport(prt);

    int n;

    while(TRUE)
    {
        ubx_raw *msg = malloc(sizeof(ubx_raw));
        uint8_t *buf = malloc(1024*sizeof(uint8_t));
        n = RS232_PollComport(cprt->nr, buf, 1024);

        msg = ubx_acquire_frombuf(buf, n);
        //PROBLEM
        free(buf);
        if (msg == NULL)
        {
            printf("Message scrambled or no message in the buffer!\n");
            free(msg);
        }
        else
        {
            printf("Length: %" PRIu16 "\n", msg->length);
        }

        free(buf);
        Sleep(1000);
        if (msg == NULL)
        {
            free(msg);
        }
    }

    return 0;
}

with the function

ubx_raw *ubx_acquire_frombuf(uint8_t *buf, int size)
{
    ubx_raw *msg = malloc(sizeof(ubx_raw));
    int n = 0;
    //sweep through bytes
    while (n < size - 1)
    {
        //check if start of message
        if ((buf[0] == UBX_SYNC1) && (buf[1] == UBX_SYNC2))
        {
            //put stuff into msg
            msg->length = ((uint16_t)*(buf+4));
            //check if full message available, otherwise
            //reduce amount to memcpy
            if (msg->length < size)
            {
                size = msg->length;
            }
            //PROBLEMATIC
            memcpy(&msg->data, &buf, size);
            return msg;
        }
        else
        {
            n++;
            continue;
        }
    }
    return NULL;
}

Whenever ubx_acquire_frombuf() is called (near the start of the while loop in main) the subsequent free(buf) gives a segfault. Clearly, something bad is happening to buf in that function. I know you can't free() stuff that isn't malloc()'d and you can't free() stuff twice. Actually, because pointers are passed by value, what goes on inside ubx_acquire_frombuf() should be irrelevant to main, right?

Anyhow, commenting out the PROBLEMATIC memcpy() (in ubx_acquire_frombuf()) removes the segfault. How so? I still want to use that memcpy! Can anyone shed some light on what's going on? memcpy() shouldn't be editing the source from which it's copying (i.e. buf), right?

P.S. apologies for not having a minimal example, but I couldn't recreate the problem from scratch. I'm not sure what's happening but there isn't anything unusual (i.e. calls to other functions written by me) in ubx_acquire_frombuf() so this isn't too far off a minimal example.


EDIT: By popular demand:

typedef struct {
  uint8_t *data;
  uint16_t length;
} ubx_raw;

3 个答案:

答案 0 :(得分:2)

您标记为有问题的代码确实存在问题:

// PROBLEMATIC
memcpy(&msg->data, &buf, size);

问题是你正在将size字节复制到字段msg->data(因为你将msg->data的地址传递给memcpy),但该字段只是一个大小的指针很小。所以memcpy将覆盖ubx_raw结构的其余部分,然后覆盖内存中的任何内容,其中包括malloc的一些内部会计信息。

你可能意味着

// PROBLEMATIC
memcpy(msg->data, &buf, size);

但这仍然有问题,因为msg->data从未初始化。所以更可能的解决方案是:

// NOT PROBLEMATIC but don't forget to free(msg->data) before free(msg).
msg->data = malloc(size); // Check for non-NULL
memcpy(msg->data, &buf, size);

答案 1 :(得分:0)

Few points that are suspicious; 1)why we are using &buf in memcpy(&msg->data, &buf, size);

2) why we are not doing buff++ in

n++;
buff++;//should be added
continue; //This is useless

3) When you do ubx_raw *msg = malloc(sizeof(ubx_raw));

I am not sure that what is memory allocated to msg->data. Or it is initialized to junk pointer.

I see many pain points but first these needs to cleared.

答案 2 :(得分:0)

My guess is that the declaration of ubx_raw is the culprit. for example, if uxb_raw is defined as

struct uxb_raw {
    uint8_t *data;
};

then the sizeof(uxb_raw) operation only returns the size of the pointer, not the size of whatever uxb_raw.data should point to. However, if you have declared

#define MAX_DATA_ARRAY_LENGTH 15
struct uxb_raw {
    uint8_t data[MAX_DATA_ARRAY_LENGTH];
};

Then sizeof(uxb_raw) will return the correct number of Bytes. If you want a malloced array of data, for example, in your main you might want to create msg like so:

struct uxb_raw msg = {.data = malloc(MAX_DATA_ARRAY_LENGTH * sizeof(uint8_t))}; 

In your ubx_acquire_frombuf function check that the *buf array size is no greater than MAX_DATA_ARRAY_LENGTH before copying data.