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

Clang 13 -O2优化输出异常而GCC正常,代码是否存在未定义行为?

问题根因

你的代码存在明确的未定义行为(UB),问题出在string_push_char函数中:

void string_push_char(String *self, char c) {
    self->len = self->len + 1;
    char *temp = realloc(self->s, self->len); // realloc返回新内存指针
    if (temp == NULL) {
        printf("Failed to allocate memory in \"string_push_char()\".\n");
        exit(-1);
    }
    // !!!这里漏掉了将新指针赋值回self->s的操作:self->s = temp;
    self->s[self->len - 2] = c; // 仍然使用已经被realloc释放的旧指针写入
    self->s[self->len - 1] = 0;
}

realloc在调整内存大小时,如果原有内存块后面没有足够的连续空间,会申请一块新的内存、拷贝原有数据、释放旧内存块,最终返回新的内存地址。你没有把新地址赋值给self->s,后续写入操作都是针对已经被释放的旧内存地址,属于**释放后使用(Use After Free)**错误。

不同编译环境表现不一致的原因

未定义行为的典型特征就是跨编译器、跨优化级别表现不稳定:

  • 低优化级别、GCC各优化级别下,realloc刚好没有移动内存块,旧指针仍然指向有效的内存地址,写入操作刚好生效,因此输出符合预期。
  • Clang开启-O2优化时,编译器会做激进的优化,realloc调用后旧指针会被标记为无效,你对旧指针的写入操作不会同步到新分配的内存块中,新内存里还是初始的空字符串,因此输出为: 5。
  • 加入-fsanitize=undefined参数后, sanitizer会替换标准库的内存分配实现,realloc的行为逻辑发生变化,不会激进地标记旧指针为无效,因此运行结果又符合预期。
问题排查方法
  • 首先开启编译告警:编译时加入-Wall -Wextra参数,Clang、GCC都会直接提示你temp变量定义后未使用,直接指向问题代码。
  • 使用内存检测工具:比如Valgrind、AddressSanitizer(编译加-fsanitize=address),运行程序会直接报出Use After Free错误,定位到出错的代码行。
  • 遇到优化级别改变就结果异常的场景,优先排查内存操作相关的未定义行为:包括指针越界、释放后使用、未初始化变量访问等。
修复方案

只需要在realloc调用成功后,将新指针赋值回self->s即可:

void string_push_char(String *self, char c) {
    self->len = self->len + 1;
    char *temp = realloc(self->s, self->len);
    if (temp == NULL) {
        printf("Failed to allocate memory in \"string_push_char()\".\n");
        exit(-1);
    }
    self->s = temp; // 新增这行
    self->s[self->len - 2] = c;
    self->s[self->len - 1] = 0;
}

内容的提问来源于stack exchange,提问作者C-W-M-Oliver8012

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 11:27:03