内存问题检测

内存检测方式

gcc/g++ 内存检测方式如下,添加一些编译标签:

  • -fsanitize=leak   检测内存泄漏。例如添加标签:-fsanitize=leak -g -O0
  • -fsanitize=address  检测内存越界。例如添加标签:-fsanitize=address -g -O2,优化级别开启 O2 也可以检测到
  • -fsanitize=undefined  检测未定义的行为,例如:使用未初始化的变量、除 0、空指针解引用等

编译完,代码跑起来后,回放录包,录包跑完后,可以按 ctrl c,会输出内存检测结果(对应的调用栈)到标准出错

【注意:这种检测方式是运行时检测,如果有些代码没有运行到,这些代码就检测不到,需要链接 asan 库,或者 export LD_PRELOAD=/lib/aarch64-linux-gnu/libasan.so.5:${LD_PRELOAD}】

使用这种方式,实际上已经帮助系统组解决了一些中间件的 coredump 问题、planning 的内存泄漏问题、perception 的内存越界问题,比较好用

其中,协助 rs_perception 杨代玉解决内存问题时,【内存越界|内存泄漏检测方法-CSDN博客】文档很好:

内存问题,出现过的 case

可能导致内存问题的原因(后续协助算法做内存问题检测时,新的 case 可以继续在下面加):

1. 释放了没有分配的内存,报错为:AddressSanitizer: attempting free on address which was not malloc()-ed

2. new 和 delete 不匹配,报错为:AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs operator delete)

new 分配一个数组,应该用 delete[] 去释放,而不是用 delete 释放

例如:auto output = std::shared_ptr(new float[num_obj * 9]);
应该改为:
auto output = std::shared_ptr(new float[num_obj * 9], [](float* p) { delete[] p; });

3. 内存越界,报错为:AddressSanitizer: heap-buffer-overflow on address 或者 AddressSanitizer: stack-buffer-overflow on address

例如:使用 for(int i = 1; i < 4; ++i) 去遍历修改数组中的对象,数组长度为 3 的话,会存在内存越界问题

4. 内存泄漏,报错为:LeakSanitizer: detected memory leaks

  • 忘记释放内存
  • 存在循环引用问题。例如伪代码如下:

    struct A {

        std::shared_ptr<struct A> sa;

        std::shared_ptr<struct A> sb;

    }

    struct B {

        std::shared_ptr<struct A> sa;

        std::shared_ptr<struct B> sb;

    }

    int main () {

        shared_ptr<A> pa(new A());

        pa->sa = pa;  // 案例一:循环引用,自己的成员指向自己,出现循环引用。释放时,无法释放 pa

        shared_ptr<B> pb(new B());

        pa->sb = pb;  // 案例二:pa->sb 指向 pb,pb->sa 指向 pa,出现循环引用。释放时,会导致 pa 和 pb 都无法释放

        pb->sa = pa;

        return 0;

    }

5. 第三方库内存 bug

如下 pcl 库的 bug,升级到 pcl1.9 可解决

==9889==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x007f6ab4eeb8 at pc 0x007f9b129370 bp 0x007c3bdf3940 sp 0x007c3bdf3960

READ of size 8 at 0x007f6ab4eeb8 thread T36

==9889==AddressSanitizer: while reporting a bug found another one. Ignoring.

    #0 0x7f9b12936f in Eigen::internal::handmade_aligned_free(void*) /usr/include/eigen3/Eigen/src/Core/util/Memory.h:118

    #1 0x7f9b12936f in Eigen::internal::aligned_free(void*) /usr/include/eigen3/Eigen/src/Core/util/Memory.h:206

    #2 0x7f9b12936f in void Eigen::internal::conditional_aligned_free<true>(void*) /usr/include/eigen3/Eigen/src/Core/util/Memory.h:259

    #3 0x7f9b12936f in void Eigen::internal::conditional_aligned_delete_auto<floattrue>(float*, unsigned long) /usr/include/eigen3/Eigen/src/Core/util/Memory.h:446

    #4 0x7f9b12936f in Eigen::DenseStorage<float, -1, -1, -10>::~DenseStorage() /usr/include/eigen3/Eigen/src/Core/DenseStorage.h:415

    #5 0x7f9b12936f in Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -10, -1, -1> >::~PlainObjectBase() /usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:98

    #6 0x7f9b12936f in Eigen::Matrix<float, -1, -10, -1, -1>::~Matrix() /usr/include/eigen3/Eigen/src/Core/Matrix.h:178

    #7 0x7f9b12936f in void Eigen::internal::call_assignment<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const>, Eigen::internal::assign_op<floatfloat> >(Eigen::Matrix<float, -1, -10, -1, -1>&, Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0constconst&, Eigen::internal::assign_op<floatfloatconst&, Eigen::internal::enable_if<Eigen::internal::evaluator_assume_aliasing<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const>, Eigen::internal::evaluator_traits<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> >::Shape>::value, void*>::type) /usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h:840

    #8 0x7f9b12936f in void Eigen::internal::call_assignment<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> >(Eigen::Matrix<float, -1, -10, -1, -1>&, Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0constconst&) /usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h:826

    #9 0x7f9b12936f in Eigen::Matrix<float, -1, -10, -1, -1>& Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -10, -1, -1> >::_set<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> >(Eigen::DenseBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> > const&) /usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:779

    #10 0x7f9b12936f in Eigen::Matrix<float, -1, -10, -1, -1>& Eigen::Matrix<float, -1, -10, -1, -1>::operator=<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> >(Eigen::DenseBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_difference_op<floatfloat>, Eigen::Matrix<float, -1, -10, -1, -1const, Eigen::Product<Eigen::Product<Eigen::Matrix<float, -1, -10, -1, -1>, Eigen::Matrix<float, -1, -10, -1, -1>, 0>, Eigen::Matrix<float, -1, -10, -1, -1>, 0const> > const&) /usr/include/eigen3/Eigen/src/Core/Matrix.h:225

    #11 0x7f9b12936f in robosense::KalmanFilter::update(Eigen::Matrix<float, -110, -11>&) /home/mogo/data/yangdaiyu/perception_ws/src/perception/lidar/robosense/modules/perception/lidar/tracking/src/filter/kalman_filter.cpp:137

6. coredump 文件,用 gdb 看到堆栈被踩坏,报错为:previous frame identical to this frame(corrupt stack?)

此时通过 gdb 看到的堆栈不一定是踩坏内存的堆栈,

栈是从高到低分配的,入栈时,sp 指针向低地址移动。假如在栈 #10 分配一个 int arr[100]。如果内存越界,例如执行了 arr[10000] = 123, 此时,10000 是高地址位,是有可能把栈踩坏的。踩坏时,不一定导致 coredump,程序继续运行,直到运行时报错,此时再看 coredump 文件,堆栈已经不是把内存踩坏时的堆栈了。

解问题方法:

    使用-fsanitize=address ,然后回放录包检测

    可以用反汇编看看,是不是把一些全局变量踩坏了,例如 futex

内存越界 demo

cat main.cpp

#include <stdio.h>

#include <string.h>

void fun(int n)

{

    printf("The %d step begin.\n", n);

    int a[10];

    for (int i = 0; i< n; i++) {

        a[i] = i;

    }

    if (n < 20) {

        fun(n +1);

    }

    printf("The %d step end\n", n);

}

int main(void)

{

    fun(8);

    return 0;

}

$ g++ main.cpp -o main -fsanitize=address -g -O2

$ ./main

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值