自定义realloc等函数出现Valgrind未初始化值错误,求修复
核心错误原因
my_realloc的根本性错误:
用my_strlen_unsigned(old_ptr) + 1获取原内存块大小完全违背realloc的设计逻辑。标准realloc不依赖内存块内容(比如是否为字符串),但你错误假设所有指针都指向以\0结尾的字符串。当内存块未初始化时(比如my_str_clean中第一次malloc(1)的块),my_strlen_unsigned会读取未初始化内存直到遇到随机的\0,直接触发Valgrind的未初始化值警告。my_memcpy的冗余判断:
循环条件中额外添加i < my_strlen_unsigned(s)完全多余,标准memcpy的职责是严格复制指定的n个字节,不管源内存是否为字符串。这个判断不仅会导致复制长度不足,还会在源内存未初始化时触发未初始化值读取。my_str_clean的初始化缺失:
第一次malloc(1)后未初始化内存,new_str中的内容是随机值,导致后续my_realloc调用时,my_strlen_unsigned读取未初始化内存。
修复后的代码
修复my_realloc
调整为仅支持字符串场景的实现,确保调用者传递的指针始终指向合法的以\0结尾的字符串:
void *my_realloc(void *ptr, size_t size) { unsigned char *old_ptr = (unsigned char *)ptr; void *new_ptr = NULL; size_t old_size = 0; if (!ptr) { return malloc(size); } if (size == 0) { free(ptr); return NULL; } // 仅当ptr指向合法的以'\0'结尾的字符串时,此逻辑有效 old_size = my_strlen_unsigned(old_ptr) + 1; new_ptr = malloc(size); if (!new_ptr) { return NULL; } // 复制原字符串内容,取原长度与新长度的较小值 my_memcpy(new_ptr, ptr, old_size < size ? old_size : size); free(ptr); return new_ptr; }
修复my_memcpy
移除冗余的字符串长度判断,严格按指定字节数复制:
void *my_memcpy(void *restrict dest, const void *restrict src, size_t n) { if (!dest || !src) return NULL; unsigned char *d = (unsigned char *)dest; const unsigned char *s = (const unsigned char *)src; size_t i = 0; while (i < n) { *d = *s; d++; s++; i++; } return dest; }
修复my_str_clean
初始化第一次malloc的内存,确保new_str始终是合法的以\0结尾的字符串:
char *my_str_clean(char *str) { char *ptr = str; char *new_str = malloc(1); size_t i = 0; if (!new_str) return NULL; // 初始化内存为合法的空字符串 new_str[0] = '\0'; while (*ptr) { if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') { new_str = my_realloc(new_str, sizeof(char) * (i + 2)); if (!new_str) { // 添加realloc失败的异常处理 free(str); return NULL; } new_str[i] = *ptr; i++; new_str[i] = '\0'; // 每次更新后保持字符串合法 } ptr++; } free(str); return new_str; }
保留原my_strlen与my_strlen_unsigned
这两个函数逻辑本身无问题,只要传入的指针指向合法的以\0结尾的字符串即可:
size_t my_strlen_unsigned(const unsigned char *s) { size_t count = 0; if (s != NULL) { while (*s != 0) { count++; s++; } } return count; } size_t my_strlen(const char *s) { size_t count = 0; if (s != NULL) { while (*s != 0) { count++; s++; } } return count; }
修复效果验证
修复后重新运行测试,Valgrind的未初始化值警告会完全消失,程序输出正确的ls-la(原测试字符串清理空格后的结果),且无内存泄漏。
内容的提问来源于stack exchange,提问作者Nayrosk

