AddressSanitizer:地址上的堆缓冲区溢出

Posted

技术标签:

【中文标题】AddressSanitizer:地址上的堆缓冲区溢出【英文标题】:AddressSanitizer: heap-buffer-overflow on address 【发布时间】:2020-04-01 12:27:16 【问题描述】:

我正在尝试编写一个函数来确定输入字符串是否有效。 此任务来自 leetcode,第 20 个任务。所以它是这样给出的。

给定一个仅包含字符 '(', ')', '', '', '[' 和 ']' 的字符串,判断输入字符串是否有效。
输入字符串在以下情况下有效:
*开括号必须用相同类型的括号封闭。
*开括号必须以正确的顺序闭合。
请注意,空字符串也被认为是有效的。

我的代码:

bool isValid(string s) 
        vector<char> str;
        map<char, char> mp;
        mp['']='';
        mp['(']=')';
        mp['[']=']';
        for(int i = 0; i < s.length(); i++)
            str.push_back(s[i]);
        int c = 0;
        while(!str.empty())
            c++;
            for(int i = 0; i < str.size(); i++)
                if(str[i+1]==mp[i])
                    int x = i+1;
                    str.erase(str.begin()+x);
                    str.erase(str.begin()+i);
                    
            if(c>str.size()) break;
        
        if(str.empty()) return true;
        else return false;
    

但是每次我得到这个错误:

================================================ ===================
==32==错误:AddressSanitizer:地址 0x602000000032 在 pc 0x00000038767f bp 0x7ffffae90390 sp 0x7ffffae90388 上的堆缓冲区溢出
在 0x602000000032 线程 T0 处读取大小 1
    #2 0x7fd5e106882f (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
0x602000000032 位于 2 字节区域右侧 0 字节 [0x602000000030,0x602000000032)
此处由线程 T0 分配:
    #4 0x7fd5e106882f (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
错误地址周围的影子字节:
  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:发发发发发发发发[02]发发发发发发发发发发
  0x0c047fff8010: 发发发发发发发发发发发发发发发发发发
  0x0c047fff8020:发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发上
  0x0c047fff8030:发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发发上
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: 发发发发发发发发发发发发发发发发发发
影子字节图例(一个影子字节代表 8 个应用程序字节):
  可寻址:00
  部分可寻址:01 02 03 04 05 06 07
  堆左红区:fa
  释放的堆区域:fd
  堆栈左红区:f1
  堆栈中间红区:f2
  堆栈右红区:f3
  返回后的堆栈:f5
  作用域后的堆栈使用:f8
  全球红区:f9
  全局初始化顺序:f6
  被用户中毒:f7
  容器溢出:fc
  数组 cookie:ac
  内部对象红区:bb
  ASan 内部:fe
  左分配红区:ca
  右分配红区:cb
  阴影间隙:cc
==32==正在中止

你能解释一下,这里出了什么问题,我的解决方案是否正确?

【问题讨论】:

您正在从str 中删除元素,因为您正在迭代它,这意味着您可能会在某些时候索引超出范围 【参考方案1】:

mp[i] 相比没有任何意义。

由于 mp 最初不包含 0,1,2,3,... 而是三个括号,因此 mp[i] 将为零,直到您的索引恰好是一个左括号字符的编码(第一个一个很可能是 40,'(' ASCII)。

如果你没有那么多字符会发生什么情况是你到达最后一次迭代,当i == size() - 1。 然后访问str[i+1] 有未定义的行为,任何事情都可能发生。

没有简单的方法可以修复您的程序,因为您的方法一开始就有缺陷,因此我建议您删除所有这些并重新开始。 (至少,您需要一种方法来跟踪您迄今为止遇到的所有左括号。主要提示:阅读std::stack

【讨论】:

以上是关于AddressSanitizer:地址上的堆缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章

NSData 转换上的堆缓冲区溢出

Address Sanitizer - 抑制 gtest

如何以编程方式获取 Linux 上的堆地址

.NET - 存储在地址空间中的堆或堆栈上的函数变量?

是否可以将 AddressSanitizer 和 ThreadSanitizer 组合成一个版本?

MFC 程序中的堆损坏