解析Valgrind输出中的"Invalid read of size"错误
Valgrind无效读取问题分析
我在测试动态存储字符串的代码时,Valgrind提示存在无效读取操作,但我认为内存分配逻辑正确,想找出被忽略的问题。
测试代码
#include <stdio.h> #include <stdlib.h> #include <string.h> char *array[4]={"str1", "str4", "str0", "str2"}; int arr_index = 0; char* get_array(void) { if (arr_index >= (sizeof(array)/sizeof(array[0]))) { return NULL; } else { return array[arr_index]; } } int main(void) { char **orderIds = malloc(0); char *tmp=NULL; int variableNumberOfElements=0; for(int i = 0; i < 10; i++) { tmp = get_array(); if(tmp == NULL) { break; } arr_index++; variableNumberOfElements++; orderIds = realloc(orderIds, variableNumberOfElements * sizeof(char*)); orderIds[i] = malloc(strlen(tmp) * sizeof(char)); strncpy(orderIds[i], tmp, strlen(tmp)); } for(int j=0; j<variableNumberOfElements; j++) { printf("%s\n", orderIds[j]); } for(int x=0; x<=variableNumberOfElements; x++) { free(orderIds[x]); } free(orderIds); exit(0); }
Valgrind输出
==27260== Memcheck, a memory error detector ==27260== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27260== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==27260== Command: ./a.out ==27260== ==27260== Invalid read of size 1 ==27260== at 0x484ED24: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==27260== by 0x48F1EE7: puts (ioputs.c:35) ==27260== by 0x109357: main (test.c:42) ==27260== Address 0x4a9c0d4 is 0 bytes after a block of size 4 alloc'd ==27260== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==27260== by 0x1092E6: main (test.c:36) ==27260== str1 str4 str0 str2 ==27260== Invalid read of size 8 ==27260== at 0x109381: main (test.c:46) ==27260== Address 0x4a9c290 is 0 bytes after a block of size 32 alloc'd ==27260== at 0x484DCD3: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==27260== by 0x1092B8: main (test.c:35) ==27260== ==27260== ==27260== HEAP SUMMARY: ==27260== in use at exit: 0 bytes in 0 blocks ==27260== total heap usage: 10 allocs, 10 frees, 1,120 bytes allocated ==27260== ==27260== All heap blocks were freed -- no leaks are possible ==27260== ==27260== For lists of detected and suppressed errors, rerun with: -s ==27260== ERROR SUMMARY: 5 errors from 2 contexts (suppressed: 0 from 0)
问题分析与修复
Valgrind的两个无效读取错误对应代码里的两个问题:
字符串未分配终止符空间
- 代码中
malloc(strlen(tmp) * sizeof(char))只分配了字符串内容的字节数,但C字符串需要末尾的'\0'标记结束。比如"str1"的长度是4,实际需要5字节存储(4个字符+1个终止符)。 - 当
printf调用strlen读取字符串时,会越过分配的内存边界寻找'\0',触发Invalid read of size 1。 - 修复:分配内存时额外预留1字节,并手动添加终止符,或者用
strdup简化操作:// 方案1:手动处理 orderIds[i] = malloc(strlen(tmp) + 1); strncpy(orderIds[i], tmp, strlen(tmp)); orderIds[i][strlen(tmp)] = '\0'; // 方案2:用strdup自动处理 orderIds[i] = strdup(tmp);
- 代码中
free循环越界访问
- 代码中
for(int x=0; x<=variableNumberOfElements; x++)的条件错误,variableNumberOfElements是数组元素个数,下标范围是0到variableNumberOfElements-1,x<=会访问orderIds[variableNumberOfElements],超出realloc分配的内存范围,触发Invalid read of size 8(64位系统指针占8字节)。 - 修复:将循环条件改为
x < variableNumberOfElements。
- 代码中
修正后的核心代码片段
// 循环内字符串分配部分 orderIds[i] = strdup(tmp); // free循环部分 for(int x=0; x < variableNumberOfElements; x++) { free(orderIds[x]); }
内容的提问来源于stack exchange,提问作者freska
相关产品推荐
相关产品推荐

