memcpy(dst, src, n) 之后的 free(src) 导致段错误
free(src) after memcpy(dst, src, n) causes a segfault
考虑以下代码:
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;
}
具有函数
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;
}
每当调用 ubx_acquire_frombuf()
时(在 main
中的 while
循环开始附近),随后的 free(buf)
会给出一个段错误。显然,该函数中的 buf
发生了一些不好的事情。我知道你不能 free()
没有 malloc()
的东西,你也不能 free()
东西两次。其实,因为指针是按值传递的,所以ubx_acquire_frombuf()
里面发生的事情应该和main无关吧?
无论如何,注释掉 PROBLEMATIC memcpy()
(在 ubx_acquire_frombuf()
中)会删除段错误。为何如此?我还想用那个memcpy
!任何人都可以阐明正在发生的事情吗? memcpy()
不应该编辑它正在复制的来源(即 buf
),对吧?
P.S。很抱歉没有一个最小的例子,但我无法从头开始重现问题。我不确定发生了什么,但在 ubx_acquire_frombuf()
中没有任何异常(即调用我编写的其他函数)所以这与最小示例相差不远。
编辑:根据大众需求:
typedef struct {
uint8_t *data;
uint16_t length;
} ubx_raw;
几点可疑;
1) 为什么我们在 memcpy(&msg->data, &buf, size);
中使用 &buf
2) 为什么我们不在
中做 buff++
n++;
buff++;//should be added
continue; //This is useless
3) 当你做 ubx_raw *msg = malloc(sizeof(ubx_raw));
我不确定分配给 msg->data 的内存是多少。或者初始化为垃圾指针。
我看到很多痛点,但首先需要清除这些痛点。
我的猜测是 ubx_raw 的声明是罪魁祸首。
例如,如果 uxb_raw
定义为
struct uxb_raw {
uint8_t *data;
};
那么 sizeof(uxb_raw)
操作只是 return 指针的大小,而不是 uxb_raw.data
应该指向的任何大小。但是,如果您已声明
#define MAX_DATA_ARRAY_LENGTH 15
struct uxb_raw {
uint8_t data[MAX_DATA_ARRAY_LENGTH];
};
然后 sizeof(uxb_raw)
将 return 正确的字节数。如果你想要一个 malloced 数据数组,例如,在你的 main 中,你可能想像这样创建 msg
:
struct uxb_raw msg = {.data = malloc(MAX_DATA_ARRAY_LENGTH * sizeof(uint8_t))};
在您的 ubx_acquire_frombuf
函数中,在复制数据之前检查 *buf 数组大小不大于 MAX_DATA_ARRAY_LENGTH
。
您标记为有问题的代码确实有问题:
// 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);
考虑以下代码:
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;
}
具有函数
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;
}
每当调用 ubx_acquire_frombuf()
时(在 main
中的 while
循环开始附近),随后的 free(buf)
会给出一个段错误。显然,该函数中的 buf
发生了一些不好的事情。我知道你不能 free()
没有 malloc()
的东西,你也不能 free()
东西两次。其实,因为指针是按值传递的,所以ubx_acquire_frombuf()
里面发生的事情应该和main无关吧?
无论如何,注释掉 PROBLEMATIC memcpy()
(在 ubx_acquire_frombuf()
中)会删除段错误。为何如此?我还想用那个memcpy
!任何人都可以阐明正在发生的事情吗? memcpy()
不应该编辑它正在复制的来源(即 buf
),对吧?
P.S。很抱歉没有一个最小的例子,但我无法从头开始重现问题。我不确定发生了什么,但在 ubx_acquire_frombuf()
中没有任何异常(即调用我编写的其他函数)所以这与最小示例相差不远。
编辑:根据大众需求:
typedef struct {
uint8_t *data;
uint16_t length;
} ubx_raw;
几点可疑; 1) 为什么我们在 memcpy(&msg->data, &buf, size);
中使用 &buf2) 为什么我们不在
中做 buff++n++;
buff++;//should be added
continue; //This is useless
3) 当你做 ubx_raw *msg = malloc(sizeof(ubx_raw));
我不确定分配给 msg->data 的内存是多少。或者初始化为垃圾指针。
我看到很多痛点,但首先需要清除这些痛点。
我的猜测是 ubx_raw 的声明是罪魁祸首。
例如,如果 uxb_raw
定义为
struct uxb_raw {
uint8_t *data;
};
那么 sizeof(uxb_raw)
操作只是 return 指针的大小,而不是 uxb_raw.data
应该指向的任何大小。但是,如果您已声明
#define MAX_DATA_ARRAY_LENGTH 15
struct uxb_raw {
uint8_t data[MAX_DATA_ARRAY_LENGTH];
};
然后 sizeof(uxb_raw)
将 return 正确的字节数。如果你想要一个 malloced 数据数组,例如,在你的 main 中,你可能想像这样创建 msg
:
struct uxb_raw msg = {.data = malloc(MAX_DATA_ARRAY_LENGTH * sizeof(uint8_t))};
在您的 ubx_acquire_frombuf
函数中,在复制数据之前检查 *buf 数组大小不大于 MAX_DATA_ARRAY_LENGTH
。
您标记为有问题的代码确实有问题:
// 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);