You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义realloc等函数出现Valgrind未初始化值错误,求修复

问题排查与修复

核心错误原因

  1. my_realloc的根本性错误:
    用my_strlen_unsigned(old_ptr) + 1获取原内存块大小完全违背realloc的设计逻辑。标准realloc不依赖内存块内容(比如是否为字符串),但你错误假设所有指针都指向以\0结尾的字符串。当内存块未初始化时(比如my_str_clean中第一次malloc(1)的块),my_strlen_unsigned会读取未初始化内存直到遇到随机的\0,直接触发Valgrind的未初始化值警告。

  2. my_memcpy的冗余判断:
    循环条件中额外添加i < my_strlen_unsigned(s)完全多余,标准memcpy的职责是严格复制指定的n个字节,不管源内存是否为字符串。这个判断不仅会导致复制长度不足,还会在源内存未初始化时触发未初始化值读取。

  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:10:28