返回字符串时触发heap-buffer-overflow运行时错误的排查
反转字符串单词时触发heap-buffer-overflow错误的排查与修复
问题背景
编写了用于反转字符串中每个单词的C语言函数reverseWords,编译运行时触发heap-buffer-overflow错误,推测问题出在if (res[i] == ' ') break;行。原始代码如下:
char * reverseWords(char * s){ int n = strlen(s); char *res = malloc(n + 1); strcpy(res,s); char temp[100]; int i = 0; int j = 0; for (i = 0; i < n; i++){ for (j = 0; j < n; j++, i++){ if (res[i] == ' ') break; temp[j] = res[i]; } while (j > 0){ j--; res[i - j - 1] = temp[j]; } } return res; }
运行时错误日志:
==30==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000005c at pc 0x5620553333a3 bp 0x7ffde02da850 sp 0x7ffde02da840 READ of size 1 at 0x60300000005c thread T0 #2 0x7f359ea9c0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) 0x60300000005c is located 0 bytes to the right of 28-byte region [0x603000000040,0x60300000005c) allocated by thread T0 here: #0 0x7f359f6e1bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8) #3 0x7f359ea9c0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) Shadow bytes around the buggy address: 0x0c067fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c067fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c067fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c067fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c067fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c067fff8000: fa fa 00 00 00 04 fa fa 00 00 00[04]fa fa fa fa 0x0c067fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c067fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c067fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c067fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c067fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==30==ABORTING
错误原因分析
- 越界访问问题:内层
for循环中,i持续自增直到遇到空格,但未判断i是否超出字符串长度n。处理最后一个单词时,循环会执行到i = n,此时访问res[i]会越界,触发heap-buffer-overflow。 - temp数组溢出风险:定义
temp[100]固定长度,若原字符串中有超过100字符的单词,会导致栈溢出。 - 外层循环的i重复自增:外层
for循环每次会让i++,但内层循环已经对i进行了多次自增,导致外层循环的i跳过部分字符,逻辑混乱。
修复后的代码
char * reverseWords(char * s) { int n = strlen(s); char *res = malloc(n + 1); if (!res) return NULL; // 检查malloc是否成功 strcpy(res, s); int start = 0; for (int i = 0; i <= n; i++) { // 遇到空格或字符串结尾时,反转当前单词 if (res[i] == ' ' || i == n) { int end = i - 1; // 原地反转单词,无需额外temp数组 while (start < end) { char temp = res[start]; res[start] = res[end]; res[end] = temp; start++; end--; } start = i + 1; // 移动到下一个单词的起始位置 } } return res; }
修复说明
- 避免越界访问:循环条件改为
i <= n,当i == n时处理最后一个单词,同时在判断空格前先检查i是否到达字符串末尾。 - 原地反转优化:去掉固定长度的
temp数组,直接在res中交换字符完成反转,避免栈溢出风险。 - 修正索引逻辑:使用
start变量记录每个单词的起始位置,避免内外层循环对i的重复修改,逻辑更清晰。
内容的提问来源于stack exchange,提问作者user20977916
相关产品推荐
相关产品推荐

