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;
答案 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.