【积土成山】AddressSanitizer: heap-buffer-overflow on address

背景,不同场景,内在原理,参考文献

一、背景

1.1 问题背景

1 在做leetcode时,总是会遇到关于“heap-buffer-overflow”的问题;
2 下面对这些场景进行归纳,提出潜在检查点,以及尝试揭示出其内在原理;

1.2 AddressSanitizer

1 快速内存错误检测工具;
2 这里还提供一种方法,进行本地安装和调试;
3 那么在之后如果leetcode不过,然后给出的堆溢出信息又不全的情况下,可以使用这种方法进行调试;

二、场景分析

2.1 自己做leetcode时,遇到的问题

1 报错现象

==46==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000030 at pc 0x000000405074 bp 0x7ffe12fc3280 sp 0x7ffe12fc3270
R
READ of size 8 at 0x603000000030 thread T0
    #2 0x7f68203db82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
0
0x603000000030 is located 0 bytes to the right of 32-byte region [0x603000000010,0x603000000030)
a
allocated by thread T0 here:
    #0 0x7f68213f6f88 in  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10bf88)
    #3 0x7f68203db82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
S
Shadow bytes around the buggy address:
char ** stringMatching(char ** words, int wordsSize, int* returnSize){
    returnSize = (int *)malloc(sizeof(int));
    int i, j, k;
    for (i = 0; i < wordsSize; i++) {
        printf("%d, %s, %p", wordsSize, words[i], &(words[i]));
    }
    *returnSize = wordsSize;
    return words;

2 READ,指出线程名是T0,操作数是READ,大小是8个byte;
‘read of size 1 at address…’
It means you read single byte form the given address
3 原因是传入的是一个二重指针,确实是可以通过访问words[i],找到其指向的内容;
但是在返回时,由于words二重指针的内容是分配在栈中,返回之后,就会删除,因此该指针返回之后,没有任何价值;
4 应该的做法是:将该指针所指向的字符串内容,重新malloc一块内存进行存储;
(64位操作系统 int和指针的长度都是八个字节)

2.2 之前同学遇到一个类似问题

1 在leetcode上做题,测试用例是过的,但是在跑全部测试用例时,出现问题,然后通过查看代码,是因为对非法入参没有判空导致;
2 然后通过修改之后,可以顺利通过;

2.3 csdn博客1

1 AddressSanitizer: heap-buffer-overflow on address 0x602000000040 at pc 0x000000406b5e bp 0x7ffc15cc0320 sp 0x7ffc15cc0318
2 LeetCode使用了AddressSanitizer检查了是否存在内存非法访问;数组访问越界,也是绝大部分的内存访问题
3 原因:把for循环内的i <= nums.size() 修改成 i < nums.size()即可
4 此外,有其他几位同学也是类似的情况,即数组越界导致;

综上,有两种途径解决类似问题
1 着重排查通过申请内存,来给指针赋值的方式,获取的数组,查看这些数组的被访问地方是否存在越界;
2 在本地安装addressSanitizer,进行本地调试,获取全部调试信息;

三、内在原理

3.1 函数入参的传递

1 传入的值,在函数所属的栈上,新分配一块空间,用于传递;
2 比如int型,那么传入的这个值,位于栈中,类似局部变量,函数退出时会释放,不会传递给外层;
3 比如int*, 传入的是整型数值所存储的地址,这样可以通过在内部修改传入指针所执行地址的值,来实现出参的传递;
4 同理,如果需要修改结构体的值,那么也需要传入能够访问到这个结构体位置的地址的值,而由于能够访问到这个结构体的位置,是一个指针,所以传入的是一个二重指针,其实本质,与int *是一致的;

3.2 malloc分配及memset的使用

int value = (int)malloc(n * sizeof(int));
(void)memset(value, 0, sizeof(n * sizeof(int));

3.3 通过strncpy拷贝字符串后,是否需要加上’\0’

strncpy举例
需要在后面,加上’\0’,不然会出现乱码,但是用strncpy_s就不会出现;

四、参考文献

1 介绍AddressSanitize
2 使用AddressSanitize在linux下进行安装和使用
3 csdn案例一
4 stackoverflow介绍告警字段含义
5 CSDN另一个总结

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值