C - 在函数中重新分配指针类型的结构成员变量。 Valgrind 报告 "Invalid read/write of size 1"
C - realloc a structs member variable of type pointer in a function. Valgrind reports "Invalid read/write of size 1"
我的问题与生成的可执行文件上的 运行 valgrind
against the following unit test below. The unit test passes when running make clean all check
, however when running valgrind
有关 我收到以下形式的错误:
Running suite(s): File System
==18845== Invalid read of size 1
==18845== at 0x4C2B8C4: strcat (vg_replace_strmem.c:303)
==18845== by 0x4E35E5F: filename_app (filename.c:196)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Address 0x6154900 is 0 bytes inside a block of size 5 free'd
==18845== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==18845== by 0x4E35E0B: filename_app (filename.c:187)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Block was alloc'd at
==18845== at 0x4C28D06: malloc (vg_replace_malloc.c:299)
==18845== by 0x52CC899: strdup (in /usr/lib64/libc-2.22.so)
==18845== by 0x4E35A31: filename_create (filename.c:44)
==18845== by 0x401815: test_filename_app (check_file_system.c:153)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
...
=18845== Invalid write of size 1
==18845== at 0x4C2B8FF: strcat (vg_replace_strmem.c:303)
==18845== by 0x4E35E5F: filename_app (filename.c:196)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Address 0x6154908 is 3 bytes after a block of size 5 free'd
==18845== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==18845== by 0x4E35E0B: filename_app (filename.c:187)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Block was alloc'd at
==18845== at 0x4C28D06: malloc (vg_replace_malloc.c:299)
==18845== by 0x52CC899: strdup (in /usr/lib64/libc-2.22.so)
==18845== by 0x4E35A31: filename_create (filename.c:44)
==18845== by 0x401815: test_filename_app (check_file_system.c:153)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
...
100%: Checks: 6, Failures: 0, Errors: 0
==18845==
==18845== HEAP SUMMARY:
==18845== in use at exit: 0 bytes in 0 blocks
==18845== total heap usage: 222 allocs, 223 frees, 62,433 bytes allocated
==18845==
==18845== All heap blocks were freed -- no leaks are possible
==18845==
==18845== For counts of detected and suppressed errors, rerun with: -v
==18845== ERROR SUMMARY: 20 errors from 7 contexts (suppressed: 0 from 0)
我的单元测试采用以下形式:
START_TEST(test_filename_app)
{
filename_t file;
// Just to check for crashes. No actual unit test.
filename_app(NULL, "frog");
file = filename_create("frog");
filename_app(&file, NULL);
ck_assert_str_eq("frog", file.name);
filename_app(&file, ".ext");
ck_assert_str_eq("frog.ext", file.name);
filename_free(&file);
}
END_TEST
如果我注释掉 filename_app(&file, ".ext");
及其相关测试,valgrind
错误就会消失。被测试的函数,传入"all forms"的是:
typedef struct {
char *name;
} filename_t;
void filename_app(filename_t *name, const char *app)
{
void *tmp = NULL;
if (name == NULL || name->name == NULL) {
return;
}
if (app == NULL) {
return;
}
size_t name_bytes_cnt = strlen(name->name);
size_t app_bytes_cnt = strlen(app);
size_t new_bytes_cnt = name_bytes_cnt + app_bytes_cnt + sizeof(char);
errno = 0;
tmp = realloc((void *)name->name, new_bytes_cnt);
if (errno == ENOMEM || tmp == NULL) {
free(tmp);
return;
}
if (tmp != name->name) {
free(tmp);
}
strcat(name->name, app);
}
我做错了什么得到一个额外的免费和无效 read/write?
假设您需要该结构,您进行的检查可能更直接:
typedef struct { char *name; } filename_t;
void filename_app(filename_t *name, const char *app)
{
if (!app || !name || !name->name ) return;
size_t name_bytes_cnt = strlen(name->name),
app_bytes_cnt = strlen(app),
new_bytes_cnt = name_bytes_cnt + app_bytes_cnt + sizeof(char);
void* tmp = realloc((void *)name->name, new_bytes_cnt);
这个:
if (tmp != name->name) {
free(tmp);
}
strcat(name->name, app);
}
没有意义。 tmp
将等于 name->name
如果 realloc
在没有移动的情况下成功,但如果 与 移动成功,则 strcat
name->name
未定义(name->name
将是 free
d 内存(free
d by realloc
))。
你的问题是
tmp = realloc((void *)name->name, new_bytes_cnt);
if (errno == ENOMEM || tmp == NULL) {
free(tmp);
return;
}
if (tmp != name->name) {
free(tmp);
}
如果 realloc()
成功并且实际执行了调整大小,则 tmp != name->name
将为真。然后您的代码释放新分配的块,而不是调整大小之前的块。
如果realloc()
失败,tmp
将是NULL
,所以没有必要传给free()
。
此外,如果 realloc()
失败,并非所有实现都将 errno
设置为 ENOMEM
(这是 POSIX 的事情,而不是 C 标准的事情)。如果 realloc()
成功,那些并不总是改变 errno
- 所以被测试的 errno
的值可能是其他一些(以前在你的程序中执行的)代码的结果,不相关到你的功能。
您也没有说明函数的调用者希望发生什么。如果 realloc()
失败,调用者是否希望保留旧值?
我的问题与生成的可执行文件上的 运行 valgrind
against the following unit test below. The unit test passes when running make clean all check
, however when running valgrind
有关 我收到以下形式的错误:
Running suite(s): File System
==18845== Invalid read of size 1
==18845== at 0x4C2B8C4: strcat (vg_replace_strmem.c:303)
==18845== by 0x4E35E5F: filename_app (filename.c:196)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Address 0x6154900 is 0 bytes inside a block of size 5 free'd
==18845== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==18845== by 0x4E35E0B: filename_app (filename.c:187)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Block was alloc'd at
==18845== at 0x4C28D06: malloc (vg_replace_malloc.c:299)
==18845== by 0x52CC899: strdup (in /usr/lib64/libc-2.22.so)
==18845== by 0x4E35A31: filename_create (filename.c:44)
==18845== by 0x401815: test_filename_app (check_file_system.c:153)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
...
=18845== Invalid write of size 1
==18845== at 0x4C2B8FF: strcat (vg_replace_strmem.c:303)
==18845== by 0x4E35E5F: filename_app (filename.c:196)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Address 0x6154908 is 3 bytes after a block of size 5 free'd
==18845== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==18845== by 0x4E35E0B: filename_app (filename.c:187)
==18845== by 0x401871: test_filename_app (check_file_system.c:157)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
==18845== Block was alloc'd at
==18845== at 0x4C28D06: malloc (vg_replace_malloc.c:299)
==18845== by 0x52CC899: strdup (in /usr/lib64/libc-2.22.so)
==18845== by 0x4E35A31: filename_create (filename.c:44)
==18845== by 0x401815: test_filename_app (check_file_system.c:153)
==18845== by 0x503D78A: ??? (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x503DB7C: srunner_run (in /usr/lib64/libcheck.so.0.0.0)
==18845== by 0x401ACE: main (check_file_system.c:196)
...
100%: Checks: 6, Failures: 0, Errors: 0
==18845==
==18845== HEAP SUMMARY:
==18845== in use at exit: 0 bytes in 0 blocks
==18845== total heap usage: 222 allocs, 223 frees, 62,433 bytes allocated
==18845==
==18845== All heap blocks were freed -- no leaks are possible
==18845==
==18845== For counts of detected and suppressed errors, rerun with: -v
==18845== ERROR SUMMARY: 20 errors from 7 contexts (suppressed: 0 from 0)
我的单元测试采用以下形式:
START_TEST(test_filename_app)
{
filename_t file;
// Just to check for crashes. No actual unit test.
filename_app(NULL, "frog");
file = filename_create("frog");
filename_app(&file, NULL);
ck_assert_str_eq("frog", file.name);
filename_app(&file, ".ext");
ck_assert_str_eq("frog.ext", file.name);
filename_free(&file);
}
END_TEST
如果我注释掉 filename_app(&file, ".ext");
及其相关测试,valgrind
错误就会消失。被测试的函数,传入"all forms"的是:
typedef struct {
char *name;
} filename_t;
void filename_app(filename_t *name, const char *app)
{
void *tmp = NULL;
if (name == NULL || name->name == NULL) {
return;
}
if (app == NULL) {
return;
}
size_t name_bytes_cnt = strlen(name->name);
size_t app_bytes_cnt = strlen(app);
size_t new_bytes_cnt = name_bytes_cnt + app_bytes_cnt + sizeof(char);
errno = 0;
tmp = realloc((void *)name->name, new_bytes_cnt);
if (errno == ENOMEM || tmp == NULL) {
free(tmp);
return;
}
if (tmp != name->name) {
free(tmp);
}
strcat(name->name, app);
}
我做错了什么得到一个额外的免费和无效 read/write?
假设您需要该结构,您进行的检查可能更直接:
typedef struct { char *name; } filename_t;
void filename_app(filename_t *name, const char *app)
{
if (!app || !name || !name->name ) return;
size_t name_bytes_cnt = strlen(name->name),
app_bytes_cnt = strlen(app),
new_bytes_cnt = name_bytes_cnt + app_bytes_cnt + sizeof(char);
void* tmp = realloc((void *)name->name, new_bytes_cnt);
这个:
if (tmp != name->name) {
free(tmp);
}
strcat(name->name, app);
}
没有意义。 tmp
将等于 name->name
如果 realloc
在没有移动的情况下成功,但如果 与 移动成功,则 strcat
name->name
未定义(name->name
将是 free
d 内存(free
d by realloc
))。
你的问题是
tmp = realloc((void *)name->name, new_bytes_cnt);
if (errno == ENOMEM || tmp == NULL) {
free(tmp);
return;
}
if (tmp != name->name) {
free(tmp);
}
如果 realloc()
成功并且实际执行了调整大小,则 tmp != name->name
将为真。然后您的代码释放新分配的块,而不是调整大小之前的块。
如果realloc()
失败,tmp
将是NULL
,所以没有必要传给free()
。
此外,如果 realloc()
失败,并非所有实现都将 errno
设置为 ENOMEM
(这是 POSIX 的事情,而不是 C 标准的事情)。如果 realloc()
成功,那些并不总是改变 errno
- 所以被测试的 errno
的值可能是其他一些(以前在你的程序中执行的)代码的结果,不相关到你的功能。
您也没有说明函数的调用者希望发生什么。如果 realloc()
失败,调用者是否希望保留旧值?