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

求解最长回文子串时触发AddressSanitizer堆缓冲区溢出错误

最长回文子串代码的Heap Buffer Overflow问题分析

问题背景

我在LeetCode上解决最长回文子串问题时,代码在DEV-C++中运行正常,但提交到LeetCode后触发了「AddressSanitizer: heap-buffer-overflow on address」运行时错误。ChatGPT修改后的代码几乎没做明显改动却能正常运行,想知道问题出在哪。

我的代码

char* longestPalindrome(char* s) {
    int i = 0;
    int j = 0;
    
    int high_i = 0;
    int high_j = 0;
    
    int maxlen = 0;
    int leng = strlen(s);
    
    for(i = 0; i < strlen(s); i++)
    {
        for(j = 0; s[i - j] == s[i + j] && (i - j) >= 0 && i + j < leng ; j++) // for odd number length palindromes
        {// checking index is not out of range
            if(((j >= high_j))) 
            {   
                high_j = j;
                high_i = i;
                
                maxlen = (2 * high_j) + 1;
            }
        }
    }
    for(i = 0; i < leng; i++)
    {
        for(j = 0; s[i - j] == s[i + j + 1] && (i - j) >= 0 && i + j < leng - 1; j++) // for even number length substrings
        {                                                                           // making sure index is not out of range
            if((j + 1) * 2 > maxlen) // compare palindrome length
            {
                high_j = j;
                high_i = i;
                maxlen = (1 + j) * 2;   
            }
        } 
    }
    char* result = malloc(sizeof(char) * (maxlen + 1)); // allocate memory for return string
    strncpy(result, s + high_i - high_j, maxlen); // start copying (i - j) to maxlen to result string
    result[maxlen] = '\0'; // end null end of string
    return result;
}

ChatGPT修正后的代码

char* longestPalindrome(char* s) {
    int i = 0;
    int j = 0;
    int high_i = 0;
    int high_j = 0;
    int maxlen = 0;
    int leng = strlen(s);

    for (i = 0; i < leng; i++) {
        for (j = 0; (i - j) >= 0 && (i + j) < leng && s[i - j] == s[i + j]; j++) {
            if (j >= high_j) {
                high_j = j;
                high_i = i;
                maxlen = (2 * high_j) + 1;
            }
        }
    }

    for (i = 0; i < leng; i++) {
        for (j = 0; (i - j) >= 0 && (i + j + 1) < leng && s[i - j] == s[i + j + 1]; j++) {
            if ((j + 1) * 2 > maxlen) {
                high_j = j;
                high_i = i;
                maxlen = (j + 1) * 2;
            }
        }
    }

    char* result = (char*)malloc(sizeof(char) * (maxlen + 1));
    strncpy(result, s + high_i - high_j, maxlen);
    result[maxlen] = '\0';
    return result;
}

错误日志

=================================================================
==22==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000000f at pc 0x55de54d7590e bp 0x7ffea23781a0 sp 0x7ffea2378190
READ of size 1 at 0x60200000000f thread T0
    #2 0x7f8076b44082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
0x60200000000f is located 1 bytes to the left of 6-byte region [0x602000000010,0x602000000016)
allocated by thread T0 here:
    #0 0x7f807778c808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #3 0x7f8076b44082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa[fa]06 fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: 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
==22==ABORTING

问题根源分析

核心问题出在条件判断顺序以及循环边界逻辑错误,直接导致了内存越界访问:

  1. 内层循环条件顺序错误
    原代码在判断回文时,先执行s[i-j] == s[i+j]或s[i-j] == s[i+j+1]的内容比较,再检查索引是否合法。当i-j为负数或i+j超出字符串长度时,已经触发了越界内存访问——这正是AddressSanitizer检测到的heap-buffer-overflow的直接原因。
    修正后的代码将索引合法性判断放在内容比较之前,只有在索引合法的前提下才会访问字符串对应位置,彻底避免了越界。

  2. 偶数长度回文的边界判断错误
    原代码偶数长度回文的内层循环条件写为i + j < leng - 1,逻辑存在漏洞,正确的边界判断应该是i + j + 1 < leng(确保右边界不越界),修正后的代码修复了这一点。

  3. 次要效率问题
    原代码第一个外层循环使用i < strlen(s),每次循环都会调用strlen,虽然不直接导致崩溃,但会降低代码效率,修正后的代码改用提前计算好的leng变量。

  4. malloc的类型转换
    修正后的代码给malloc添加了(char*)强制类型转换,这在C++环境下是必要的,但在C环境下不是必须的,不属于崩溃的原因。

总结

DEV-C++默认未开启内存越界检测,因此代码的潜在问题没有暴露;而LeetCode的AddressSanitizer会严格检测这类不安全的内存访问行为。崩溃的核心原因是先访问内存再检查索引合法性的错误逻辑,修正后即可正常运行。

内容的提问来源于stack exchange,提问作者bleckemr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:04:57