为什么 Valgrind 抱怨 fgets?
Why Valgrind complains about fgets?
我有一个简单的C代码。
main.c
int main() {
FILE *stream = fopen("../input.txt", "r");
cube test_cube;
cube_initialization(&test_cube, stream);
/* and some code with free memory which is not needed to understand the situation */
}
cube.c
/* just the function valgrind complains about */
void cube_initialization(cube *cube, FILE *input_file) {
int side_length;
char buffer[BUF_SIZE];
char waste_buffer[BUF_SIZE];
fgets(buffer, BUF_SIZE, input_file);
fgets(waste_buffer, BUF_SIZE, input_file); /* empty line */
side_length = (int) strtol(buffer, NULL, 10);
cube->side_length = side_length;
cube->cube_array = malloc(side_length * sizeof(int **));
int z;
for (z = 0; z < side_length; z++) {
cube->cube_array[z] = malloc(side_length * sizeof(int *));
int y;
for (y = 0; y < side_length; y++) {
cube->cube_array[z][y] = malloc(side_length * sizeof(int));
}
}
}
和 valgrind 输出
==8251== Invalid read of size 4
==8251== at 0x48F3727: fgets (iofgets.c:47)
==8251== by 0x1093C2: cube_initialization (cube.c:11)
==8251== by 0x10928D: main (main.c:11)
==8251== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8251==
==8251==
==8251== Process terminating with default action of signal 11 (SIGSEGV)
==8251== Access not within mapped region at address 0x0
==8251== at 0x48F3727: fgets (iofgets.c:47)
==8251== by 0x1093C2: cube_initialization (cube.c:11)
==8251== by 0x10928D: main (main.c:11)
==8251== If you believe this happened as a result of a stack
==8251== overflow in your program's main thread (unlikely but
==8251== possible), you can try to increase the size of the
==8251== main thread stack using the --main-stacksize= flag.
==8251== The main thread stack size used in this run was 8388608.
==8251==
==8251== HEAP SUMMARY:
==8251== in use at exit: 0 bytes in 0 blocks
==8251== total heap usage: 1 allocs, 1 frees, 488 bytes allocated
==8251==
==8251== All heap blocks were freed -- no leaks are possible
==8251==
==8251== For lists of detected and suppressed errors, rerun with: -s
==8251== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
我不明白为什么 Valgrind 会抱怨 fgets()
。我从文件中读取数据并使用 fgets
和指向大缓冲区 (256) 的指针,但它只需要我读取大约 1-6 个符号的短行(我需要 fgets,因为它在找到 '\n' 时停止行结束)。也许问题在于 fgets() 试图读取 256 个符号的行,它在 1-5 和 '\n'?
之后停止
Valgrind 抱怨非法地址 0x0
访问:
Address 0x0 is not stack'd, malloc'd or (recently) free'd
在你的fgets()
通话中
fgets(buffer, BUF_SIZE, input_file);
buffer
参数很好,因为它是在堆栈中分配的。唯一负责的可能是来自 main()
的 input_file
参数。该参数是从 fopen()
调用中获得的流。在传递给 cube_initialization()
!
之前你没有检查它
检查一下,然后明白为什么它returns NULL(可能你试图打开一个不存在的路径)。
int main() {
FILE *stream = fopen("../input.txt", "r");
cube test_cube;
if( stream != NULL )
{
cube_initialization(&test_cube, stream);
/* Continue execution*/
}
}
Valgrind 抱怨 fgets()
中的读取无效。问题不太可能是目标数组的大小,这可能会触发无效写入,但确实是一个 BUF_SIZE
字节的数组,您将其记录为合理的值 256。问题更有可能是流指针,如 Valgrind 所报告的那样可能为空:
Address 0x0 is not stack'd, malloc'd or (recently) free'd`
您应该修复代码中潜在的未定义行为:
- 验证
fopen()
return 是否有效 FILE*
,以避免在您尝试读取 input_file
. 时出现未定义的行为
- 验证
fgets()
成功(不 return NULL
),以避免从目标数组读取时出现未定义的行为。
我有一个简单的C代码。
main.c
int main() {
FILE *stream = fopen("../input.txt", "r");
cube test_cube;
cube_initialization(&test_cube, stream);
/* and some code with free memory which is not needed to understand the situation */
}
cube.c
/* just the function valgrind complains about */
void cube_initialization(cube *cube, FILE *input_file) {
int side_length;
char buffer[BUF_SIZE];
char waste_buffer[BUF_SIZE];
fgets(buffer, BUF_SIZE, input_file);
fgets(waste_buffer, BUF_SIZE, input_file); /* empty line */
side_length = (int) strtol(buffer, NULL, 10);
cube->side_length = side_length;
cube->cube_array = malloc(side_length * sizeof(int **));
int z;
for (z = 0; z < side_length; z++) {
cube->cube_array[z] = malloc(side_length * sizeof(int *));
int y;
for (y = 0; y < side_length; y++) {
cube->cube_array[z][y] = malloc(side_length * sizeof(int));
}
}
}
和 valgrind 输出
==8251== Invalid read of size 4
==8251== at 0x48F3727: fgets (iofgets.c:47)
==8251== by 0x1093C2: cube_initialization (cube.c:11)
==8251== by 0x10928D: main (main.c:11)
==8251== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8251==
==8251==
==8251== Process terminating with default action of signal 11 (SIGSEGV)
==8251== Access not within mapped region at address 0x0
==8251== at 0x48F3727: fgets (iofgets.c:47)
==8251== by 0x1093C2: cube_initialization (cube.c:11)
==8251== by 0x10928D: main (main.c:11)
==8251== If you believe this happened as a result of a stack
==8251== overflow in your program's main thread (unlikely but
==8251== possible), you can try to increase the size of the
==8251== main thread stack using the --main-stacksize= flag.
==8251== The main thread stack size used in this run was 8388608.
==8251==
==8251== HEAP SUMMARY:
==8251== in use at exit: 0 bytes in 0 blocks
==8251== total heap usage: 1 allocs, 1 frees, 488 bytes allocated
==8251==
==8251== All heap blocks were freed -- no leaks are possible
==8251==
==8251== For lists of detected and suppressed errors, rerun with: -s
==8251== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
我不明白为什么 Valgrind 会抱怨 fgets()
。我从文件中读取数据并使用 fgets
和指向大缓冲区 (256) 的指针,但它只需要我读取大约 1-6 个符号的短行(我需要 fgets,因为它在找到 '\n' 时停止行结束)。也许问题在于 fgets() 试图读取 256 个符号的行,它在 1-5 和 '\n'?
Valgrind 抱怨非法地址 0x0
访问:
Address 0x0 is not stack'd, malloc'd or (recently) free'd
在你的fgets()
通话中
fgets(buffer, BUF_SIZE, input_file);
buffer
参数很好,因为它是在堆栈中分配的。唯一负责的可能是来自 main()
的 input_file
参数。该参数是从 fopen()
调用中获得的流。在传递给 cube_initialization()
!
检查一下,然后明白为什么它returns NULL(可能你试图打开一个不存在的路径)。
int main() {
FILE *stream = fopen("../input.txt", "r");
cube test_cube;
if( stream != NULL )
{
cube_initialization(&test_cube, stream);
/* Continue execution*/
}
}
Valgrind 抱怨 fgets()
中的读取无效。问题不太可能是目标数组的大小,这可能会触发无效写入,但确实是一个 BUF_SIZE
字节的数组,您将其记录为合理的值 256。问题更有可能是流指针,如 Valgrind 所报告的那样可能为空:
Address 0x0 is not stack'd, malloc'd or (recently) free'd`
您应该修复代码中潜在的未定义行为:
- 验证
fopen()
return 是否有效FILE*
,以避免在您尝试读取input_file
. 时出现未定义的行为
- 验证
fgets()
成功(不 returnNULL
),以避免从目标数组读取时出现未定义的行为。