精华内容
下载资源
问答
  • C++内存错误检测工具

    千次阅读 2017-12-24 14:09:45
    C++内存错误检测工具 简介 1)开发时,该如何尽力避免内存错误的发生; 2)开发后,该如何去确定真的没有问题; 相关内容 1)内存使用方式简介; 2)使用智能指针降低内存泄露的风险; 3)windows上,使用...

    C++内存错误检测工具


    简介
    1)开发时,该如何尽力避免内存错误的发生;
    2)开发后,该如何去确定真的没有问题;


    相关内容
    1)内存使用方式简介;
    2)使用智能指针降低内存泄露的风险;
    3)windows上,使用Visual Studio做内存错误检测;
    4)Linux上,使用Valgrind做内存错误检测;


    问题引出
    昨天遇到了一个大牛,学到了不少东西。其中一些东西就是关于内存泄露的。对话大概是这样的。
    大牛:”你怎么保证自己的代码没有内存泄露。”
    我:”!@#$%^&*!(大概说的是,只要注意一点,不会出现的)”
    大牛:”呵呵,你用什么证明。”


    一、内存使用方式简介
    1、代码段:只读数据;

    2、数据段/BSS段:如果没有显式初始化,会被初始化为零;

    3、栈空间数据:
    一般指局部变量。这类变量若未初始化,则会被赋予随机的初值。
    如果在栈中申请过大的局部变量,会出现栈溢出。

    4、堆空间数据:
    出现内存错误的情况可以有两种:
    1)申请了一块内存,但未释放,俗称内存泄露;
    2)对于同一块内存,释放了多次;

    5、其它
    1)野指针:一般指未初始化或已释放的指针。若去访问这个指针,将出错;
    2)越界访问:通常在使用数组时被强调;
    3)只读的数据和资源:如果去写了,也就错了;
    4)访问超出控制范围的内存:比如先保存一个局部变量的地址,超出它的作用域之后,又去访问这个地址;


    二、使用智能指针降低内存泄露的风险
    有人说,”如果可以,尽量使用智能指针。”也有人说,”如果项目的大多数代码都用的指针,那就别用智能指针,不然显得乱。”


    在可以使用智能指针的场景中,智能指针需要尽可能的替代指针的存在。

    以shared_ptr<Type>为例,
    Type * ptr  =>  shared_ptr<Type> ptr
    new Type()  =>  make_shared<Type>()
    delete ptr  =>  智能指针会自动释放


    三、windows上,使用Visual Studio做内存错误检测
    当一个观点无法被直接证明的时候,我们可以采用旁证,即借助大家都相信的东西来间接证明。在内存错误方面,我们可以使用第三方工具来进行检测。


    在windows上,Visual Studio是最常用的开发工具,也可以用来检测内存错误。它提供的功能有很多,都可以在crtdbg.h文件中找到。


    最简单直接的一种使用方式,是将内存泄露的代码位置打印出来。
    具体方法,就是在代码前加几行代码,像这样:

    #include <crtdbg.h>
    #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
    static int tmp = _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );


    假设测试代码如下:

    #ifdef _MSC_VER
    #ifdef _DEBUG
    #include <crtdbg.h>
    #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
    static int tmp = _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    #endif
    #endif
    
    int main()
    {
        char * ptr = new char;  
        return 0;
    }


    以debug模式编译运行后,在输出窗口可以看到:

    Detected memory leaks!
    Dumping objects ->
    xxx\main.cpp(14) : {75} normal block at 0x0102AFD8, 1 bytes long.
     Data: < > CD 
    Object dump complete.


    或者可以用另一种写法,在这里可以看到。大体上是一样的,只是做了一些处理,方便使用。


    四、Linux上,使用Valgrind做内存错误检测
    如果不使用第三方工具,g++本身其实也可以做很多内存错误方面的检测工作。只需要在编译时,加入-Wall选项,它就会尽可能的打印出警告信息。这其中就包含了很多内存错误的警告。

    再回到使用第三方工具的话题。在Linux上,可以使用Valgrind做内存错误检测。老样子,先从简单的用法开始。可以像这样:

    sudo apt-get install valgrind
    
    valgrind --tool=memcheck --show-reachable=yes --read-var-info=yes \
    --verbose --time-stamp=yes --leak-check=full --log-file=logfile.log <debug编译的可执行文件>


    执行过后,我们可以再logfile.log里查看内存错误检测结果。查阅时,可以先搜索关键字ERROR。这样可以很快的定位到相关信息,包括错误代码位置,错误原因等。


    上面的命令包含三个部分,即valgrind,一系列选项,可执行文件。首先需要注意的是,这个可执行文件是debug模式编译的。如:

    g++ -o test test.cpp -Wall -g


    然后是这些选项,这里给出的并不全,但可用。

    1. --tool=<toolname> [default: memcheck]
        valgrind是一套工具的集合,memcheck是较为常用的一个,作为默认选择;
    
    2. --show-reachable=yes
        对于控制范围之外的内存泄漏也进行检测,如全局指针、static指针等;
    
    3. --read-var-info=yes
        应用程序会变慢,但是能给出更多的错误细节;
    
    4. --verbose
        打印更详细的信息;
    
    5. --time-stamp=yes
        顾名思义,显示时间戳;
    
    6. --leak-check=full
        展示内存泄露的细节,比如在代码中的位置;
    
    7. --log-file=logfile.log
        将valgrind的打印信息输出到指定文件中,否则在直接标准输出;


    五、说明
    若有兴趣,可以看看下面的地址。里面的代码可以作为备用组件。
    https://github.com/Jiacheng03/MemLeakDetector

    展开全文
  • 该文章首发于微信公众号:字节流动 什么是 ASan ASan 是 Address Sanitizer 简称,它是是一种基于编译器用于快速检测原生代码中内存错误的工具。 简而言之,ASan 就是一个用于快速检测内存...ASan 可以检测到内存..

    NDK (C++) 开发中如何使用 ASan 检测内存越界、溢出等内存错误

    该文章首发于微信公众号:字节流动

    什么是 ASan

    ASan 是 Address Sanitizer 简称,它是是一种基于编译器用于快速检测原生代码中内存错误的工具。

    简而言之,ASan 就是一个用于快速检测内存错误的工具。这里很多朋友有误解,ASan 其实并不能用于内存泄漏检测,Android 平台内存泄漏检测推荐 MallocDebug 。

    另外需要注意的是 Android O(API >= 27)及以上版本才支持 ASan ,NDK 需要选用 r20 及以上版本。

    ASan 可以检测到内存错误类型如下:

    • Stack and heap buffer overflow/underflow 栈和堆缓冲区上溢/下溢;
    • Heap use after free 堆内存被释放之后还在使用其指针;
    • Stack use outside scope 在某个局部变量的作用域之外,使用其指针;
    • Double free/wild free 指针重复释放的情况。

    ASan 支持 arm 和 x86 平台,使用 ASan 时,APP 性能会变慢且内存占用会飙升。针对 arm64 平台,Android 官方推荐使用 HWAddress Sanitizer (HWASan),后面会介绍。

    关于 ASan 的原理本文不做深入讨论,该文章的主要目的是帮助开发者快速上手 ASan 的使用。

    这里感性地介绍下 ASan 的工作原理:ASan 相当于接管了内存的分配,当分配一块内存时,会在这块内存的前后添加"标志位",然后再次使用该内存的时候检查"标志位"是否被修改,当发现"标志位"被修改时,判断出现内存错误。

    怎么使用 ASan

    之所以写这篇文件,就是因为发现一些文章介绍 ASan 使用方法搞得非常复杂,不易上手。

    其实 Android 官方的使用说明非常简洁,就是复制黏贴,添加两行代码就搞定。

    官方文档:https://developer.android.com/ndk/guides/asan

    修改编译脚本

    CMake

    APP 下面的 build.gradle 添加:

    android {
        defaultConfig {
            externalNativeBuild {
                cmake {
                    # Can also use system or none as ANDROID_STL.
                    arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
                }
            }
        }
    }
    

    CMakeLists.txt 脚本添加:

    target_compile_options(${libname} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
    set_target_properties(${libname} PROPERTIES LINK_FLAGS -fsanitize=address)
    

    NDK-BUILD

    Application.mk 文件添加:

    APP_STL := c++_shared # Or system, or none.
    APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
    APP_LDFLAGS := -fsanitize=address
    

    Android.mk 文件添加:

    APP_STL := c++_shared # Or system, or none.
    APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
    APP_LDFLAGS := -fsanitize=address
    

    拷贝 Asan 库到 jniLibs 目录下

    Asan 库位于下面路径下:

    android-ndk-r21\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\9.0.8\lib\linux
    

    64 位 libclang_rt.asan-aarch64-android.so , 32 位 libclang_rt.asan-arm-android.so ,分别拷贝两个库到 jniLibs 相应的目录下。

    新建 wrap.sh 文件,拷贝下面内容到文件中:

    #!/system/bin/sh
    HERE="$(cd "$(dirname "$0")" && pwd)"
    export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1
    ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so)
    if [ -f "$HERE/libc++_shared.so" ]; then
        # Workaround for https://github.com/android-ndk/ndk/issues/988.
        export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
    else
        export LD_PRELOAD="$ASAN_LIB"
    fi
    "$@"
    

    在 main 文件夹下新建目录 resources\lib 然后将 wrap.sh 文件拷贝到相应的目录下面,最终的目录结构是这样的:

    <project root>
    └── app
        └── src
            └── main
                ├── jniLibs
                │   ├── arm64-v8a
                │   │   └── libclang_rt.asan-aarch64-android.so
                │   ├── armeabi-v7a
                │   │   └── libclang_rt.asan-arm-android.so
                │   ├── x86
                │   │   └── libclang_rt.asan-i686-android.so
                │   └── x86_64
                │       └── libclang_rt.asan-x86_64-android.so
                └── resources
                    └── lib
                        ├── arm64-v8a
                        │   └── wrap.sh
                        ├── armeabi-v7a
                        │   └── wrap.sh
                        ├── x86
                        │   └── wrap.sh
                        └── x86_64
                            └── wrap.sh
    

    自此 ASan 接入完成,是不是很简单?

    ASan 检测内存错误

    这一节我们在代码中故意设置一些常见的内存错误(内存越界等)用来测试 ASan 检测出来的结果是否正确。需要注意的是,当 ASan 检测出内存错误,程序就会立即 crash ,不再往下执行,log 中会出现关键字 AddressSanitizer 。

    堆内存溢出

    static void HeapBufferOverflow() {
        int *arr = new int[1024];
        arr[0] = 11;
        arr[1024] = 12;
        LOGCATE("HeapBufferOverflow arr[0]=%d, arr[1024]",arr[0], arr[1024]);
    }
    

    ASan 检测结果(crash log)中出现关键字 heap-buffer-overflow :

    05-13 19:52:16.247  4194  4194 I com.byteflow.learnffmpeg: =================================================================
    05-13 19:52:16.247  4194  4194 I com.byteflow.learnffmpeg: ==4194==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x004f0d5a8100 at pc 0x0074f822b648 bp 0x007ff0227a00 sp 0x007ff02279f8
    05-13 19:52:16.247  4194  4194 I com.byteflow.learnffmpeg: WRITE of size 4 at 0x004f0d5a8100 thread T0
    05-13 19:52:16.257 23334 23334 D Launcher_UnlockAnimationStateMachine: mResetIdleStateRunnable
    05-13 19:52:16.265  4194  4194 I com.byteflow.learnffmpeg:     #0 0x74f822b644  (/data/app/com.byteflow.learnffmpeg-mVg7CcQSTXVnJhfo7u0XLA==/lib/arm64/liblearn-ffmpeg.so+0x146644)
    05-13 19:52:16.265  4194  4194 I com.byteflow.learnffmpeg:     #1 0x74f8229b20  (/data/app/com.byteflow.learnffmpeg-mVg7CcQSTXVnJhfo7u0XLA==/lib/arm64/liblearn-ffmpeg.so+0x144b20)
    05-13 19:52:16.265  4194  4194 I com.byteflow.learnffmpeg:     #2 0x74f8229a7c  (/data/app/com.byteflow.learnffmpeg-mVg7CcQSTXVnJhfo7u0XLA==/lib/arm64/liblearn-ffmpeg.so+0x144a7c)
    05-13 19:52:16.265  4194  4194 I com.byteflow.learnffmpeg:     #3 0x74fdaac0a0  (/data/app/com.byteflow.learnffmpeg-mVg7CcQSTXVnJhfo7u0XLA==/oat/arm64/base.odex+0xb0a0)
    05-13 19:52:16.265  4194  4194 I com.byteflow.learnffmpeg: ........
    

    栈内存溢出

     //stack-buffer-overflow
     static void StackBufferOverflow() {
         int arr[1024];
         arr[0] = 11;
         arr[1024] = 12;
         LOGCATE("StackBufferOverflow arr[0]=%d, arr[1024]",arr[0], arr[1024]);
     }
    

    ASan 检测结果(crash log)中出现关键字 stack-buffer-overflow :

    05-13 19:54:30.371  5002  5002 I com.byteflow.learnffmpeg: =================================================================
    05-13 19:54:30.371  5002  5002 I com.byteflow.learnffmpeg: ==5002==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x007ff02278c0 at pc 0x0074f8bd6640 bp 0x007ff0226890 sp 0x007ff0226888
    05-13 19:54:30.372  5002  5002 I com.byteflow.learnffmpeg: WRITE of size 4 at 0x007ff02278c0 thread T0
    05-13 19:54:30.389  5002  5002 I com.byteflow.learnffmpeg:     #0 0x74f8bd663c  (/data/app/com.byteflow.learnffmpeg-aaLGh4G_-2c2WC7sX0ibag==/lib/arm64/liblearn-ffmpeg.so+0x14663c)
    05-13 19:54:30.389  5002  5002 I com.byteflow.learnffmpeg:     #1 0x74f8bd4a20  (/data/app/com.byteflow.learnffmpeg-aaLGh4G_-2c2WC7sX0ibag==/lib/arm64/liblearn-ffmpeg.so+0x144a20)
    05-13 19:54:30.389  5002  5002 I com.byteflow.learnffmpeg:     #2 0x74f8bd497c  (/data/app/com.byteflow.learnffmpeg-aaLGh4G_-2c2WC7sX0ibag==/lib/arm64/liblearn-ffmpeg.so+0x14497c)
    ......
    

    使用已释放的指针

    //heap-use-after-free
    static void UseAfterFree() {
        int *arr = new int[1024];
        arr[0] = 11;
        delete [] arr;
        LOGCATE("UseAfterFree arr[0]=%d, arr[1024]",arr[0], arr[1024]);
    }
    

    ASan 检测结果(crash log)中出现关键字 heap-use-after-free :

    05-13 19:56:44.430  5235  5235 I com.byteflow.learnffmpeg: =================================================================
    05-13 19:56:44.430  5235  5235 I com.byteflow.learnffmpeg: ==5235==ERROR: AddressSanitizer: heap-use-after-free on address 0x004f0d5a7100 at pc 0x0074f7ac945c bp 0x007ff02279d0 sp 0x007ff02279c8
    05-13 19:56:44.430  5235  5235 I com.byteflow.learnffmpeg: READ of size 4 at 0x004f0d5a7100 thread T0
    05-13 19:56:44.447  5235  5235 I com.byteflow.learnffmpeg:     #0 0x74f7ac9458  (/data/app/com.byteflow.learnffmpeg-w2WNuKKPLEj7i4_8_Oj3Sw==/lib/arm64/liblearn-ffmpeg.so+0x146458)
    05-13 19:56:44.448  5235  5235 I com.byteflow.learnffmpeg:     #1 0x74f7ac7920  (/data/app/com.byteflow.learnffmpeg-w2WNuKKPLEj7i4_8_Oj3Sw==/lib/arm64/liblearn-ffmpeg.so+0x144920)
    05-13 19:56:44.448  5235  5235 I com.byteflow.learnffmpeg:     #2 0x74f7ac787c  (/data/app/com.byteflow.learnffmpeg-w2WNuKKPLEj7i4_8_Oj3Sw==/lib/arm64/liblearn-ffmpeg.so+0x14487c)
    ......
    

    局部变量的作用域之外使用其指针

    //stack-use-after-scope
    static int *p;
    static void UseAfterScope()
    {
        {
            int a = 0;
            p = &a;
        }
        *p = 1111;
        LOGCATE("UseAfterScope *p=%d",*p);
    }
    

    ASan 检测结果(crash log)中出现关键字 stack-use-after-scope :

    https://developer.android.com/ndk/guides/asan#cmake05-13 20:01:19.447  5907  5907 I com.byteflow.learnffmpeg: =================================================================
    05-13 20:01:19.447  5907  5907 I com.byteflow.learnffmpeg: ==5907==ERROR: AddressSanitizer: stack-use-after-scope on address 0x007ff02279a0 at pc 0x0074f8236438 bp 0x007ff0227970 sp 0x007ff0227968
    05-13 20:01:19.448  5907  5907 I com.byteflow.learnffmpeg: WRITE of size 4 at 0x007ff02279a0 thread T0
    05-13 20:01:19.462 23334 23334 D Launcher_UnlockAnimationStateMachine: mResetIdleStateRunnable
    05-13 20:01:19.464  5907  5907 I com.byteflow.learnffmpeg:     #0 0x74f8236434  (/data/app/com.byteflow.learnffmpeg-jx_Xi14rwGHag_VZ9KWXYA==/lib/arm64/liblearn-ffmpeg.so+0x146434)
    05-13 20:01:19.465  5907  5907 I com.byteflow.learnffmpeg:     #1 0x74f8234860  (/data/app/com.byteflow.learnffmpeg-jx_Xi14rwGHag_VZ9KWXYA==/lib/arm64/liblearn-ffmpeg.so+0x144860)
    05-13 20:01:19.465  5907  5907 I com.byteflow.learnffmpeg:     #2 0x74f82347bc  (/data/app/com.byteflow.learnffmpeg-jx_Xi14rwGHag_VZ9KWXYA==/lib/arm64/liblearn-ffmpeg.so+0x1447bc)
    05-13 20:01:19.465  5907  5907 I com.byteflow.learnffmpeg:     #3 0x74fdabe0a0  (/data/app/com.byteflow.learnffmpeg-jx_Xi14rwGHag_VZ9KWXYA==/oat/arm64/base.odex+0xb0a0)
    .....
    

    重复释放指针

    //double-free
    static void DoubleFree() {
        int *arr = new int[1024];
        arr[0] = 11;
        delete [] arr;
        delete [] arr;
        LOGCATE("UseAfterFree arr[0]=%d",arr[0]);
    }
    

    ASan 检测结果(crash log)中出现关键字 double-free :

    05-13 20:02:16.474  6102  6102 I com.byteflow.learnffmpeg: =================================================================
    05-13 20:02:16.475  6102  6102 I com.byteflow.learnffmpeg: ==6102==ERROR: AddressSanitizer: attempting double-free on 0x004f0d5a7100 in thread T0:
    05-13 20:02:16.492  6102  6102 I com.byteflow.learnffmpeg:     #0 0x74f9f2b7b0  (/data/app/com.byteflow.learnffmpeg-kjj44NZxl-eyA06gf3E2MA==/lib/arm64/libclang_rt.asan-aarch64-android.so+0xd57b0)
    05-13 20:02:16.492  6102  6102 I com.byteflow.learnffmpeg:     #1 0x74f88cd210  (/data/app/com.byteflow.learnffmpeg-kjj44NZxl-eyA06gf3E2MA==/lib/arm64/liblearn-ffmpeg.so+0x146210)
    05-13 20:02:16.492  6102  6102 I com.byteflow.learnffmpeg:     #2 0x74f88cb720  (/data/app/com.byteflow.learnffmpeg-kjj44NZxl-eyA06gf3E2MA==/lib/arm64/liblearn-ffmpeg.so+0x144720)
    05-13 20:02:16.492  6102  6102 I com.byteflow.learnffmpeg:     #3 0x74f88cb67c  (/data/app/com.byteflow.learnffmpeg-kjj44NZxl-eyA06gf3E2MA==/lib/arm64/liblearn-ffmpeg.so+0x14467c)
    ......
    

    ASan 基本上可以覆盖到常见的内存错误问题,还有其他 Case 就不一一展示了。

    技术交流

    技术交流可以添加我的个人微信:Byte-Flow

    联系我

    展开全文
  • C++常见内存错误汇总

    千次阅读 2017-04-19 20:31:53
    C++中内存错误通常属于运行时错误,只有在程序运行时才能发现,编译器无法自动检测到内存错误。多数情况下是程序逻辑或者参数存在某些错误。下面总结一下C++常见的内存错误: 1. 内存泄露 内存泄露是指应用...
    C++中内存错误通常属于运行时错误,只有在程序运行时才能发现,编译器无法自动检测到内存错误。多数情况下是程序逻辑或者参数存在某些错误。下面总结一下C++常见的内存错误:

    1. 内存泄露

    内存泄露是指应用程序未释放动态申请的且不再使用的内存,原因可能是程序员疏忽或者错误造成程序异常。

    在C/C++中,动态申请的内存是在堆上的。内存管理器也不会自动回收不再使用的内存,也就是说如果忘记释放动态申请的内存,该内存区域是不允许重用的。如果发送此类的内存泄露,函数每执行一次就丢失一块内存。长时间运行改程序可能引起系统"内存耗尽"。

    这个问题本身没有很好的解决思路。只能从编程习惯上入手,也就是说动态申请内存与释放内存必须匹配,亦即new和delete的调用次数必须相同。



    2. 野指针

    未初始化的指针称为野指针(另一种说法是指向不可用内存区域的指针,不过笔者认为前者更合适)。通常对野指针进行写操作会发生不可预知的错误。

    通常的避免方法就是在指针定义的时候就初始化,初始为NULL或者一个有意义的内存地址。对于动态申请的内存地址,在该内存释放之后,对应指针最好立即赋值为NULL。并在具体使用指针的时候判断指针的值是否有效(通常检测是否为NULL)。



    3. 内存越界访问

    内存越界访问通常发生在数组、字符串或者连续内存的访问。有两种情况:

    读越界,即读了非有效的数据。如果所读的内存地址是无效的,程序会立即崩溃。如果所读内存地址是有效的,读入的时候不会有错误,但是读入的数据是随机的,可能会产生不可控制的后果。举个简单的例子,字符串的输出,如果没有结束符,会输出一堆乱码也可能输出正常,也就是说结果是不可控的。

    写越界,亦称为缓冲区溢出,通常写越界会发生错误。内存写越界造成的后果是非常严重的。例如访问数组越界可能会修改访问数组的循环变量,造成死循环。另一个比较经典的例子就是缓冲区溢出攻击,试试上就是利用越界修改程序的栈空间,达到控制操作系统或者执行某些特定任务的目的。

    这类问题几乎没有很有效的解决思路,只能由程序员控制好内存的访问,小心处理各种内存有关的操作。



    4. 返回指向临时变量的指针

    最经典的例子是一道面试题中关于字符串指针的返回函数,代码如下:

    char * getString(){char b[] = "Hello, Tocy!"; return b;}

    栈里面的变量都是临时的,函数执行完成之后,相关的临时变量和参数都会被清除。这也是程序不允许返回指向这些临时变量的指针的原因,因为函数执行结束后这些指针指向的数据是随机的,给程序造成不可预知的后果。

    通常此类错误编译器会给出警告。解决思路很简单,在任何情况下不要返回函数的局部变量的任何指针,如果需要传递参数可以考虑使用返回值、参数或者全局变量(不推荐)。



    5. 试图修改常量

    在普通变量前面加上const修饰符,只是给编译器做类型检查用的。编译器禁止修改这样的变量,但这并不是强制的,完全可以用强制类型转换来处理,一般不会出错。例如下面代码:

    int func(void){ const int IMAX = 3; int * pi = (int *)(&IMAX); *pi = 4; cout << IMAX << endl;}

    笔者在vc6和vs2008下运行该函数,输出都是3,编译运行没有任何错误和警告。至于有没有修改常量的值,有兴趣的读者可以自己看看反汇编的代码,相信你就会明白是否修改了常量的值(最终结果是修改了,只是编译器做了某些优化所以输出依然不变。)。

    而对于全局常量和字符串使用强制类型转来处理在运行时仍然会出错,这是因为它们是存放在只读内存区("rodata"),只读内存区是不允许修改的。试图对其修改,会引发内存错误。

    所以针对这种类型错误,笔者建议最好不要修改常量,除非万不得已。



    6. 内存未分配成功,但已经使用

    通常是由于程序员认为动态内存分配不会失败。解决思路很简单,在使用动态申请的内存时,首先检测指针是否为NULL(通常动态内存分配失败会返回空指针)。



    7. 内存分配成功,但没有初始化

    犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。

    内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

    当然发生这种情况还有另外一个可能就是在动态创建类对象时类构造函数抛出异常(即申请动态内存成功,但是调用构造函数失败)。



    另外如果出现下图


    基本可以断定是内存问题,极有可能是指针异常引起的。当然还有其他原因,需要视具体情况而定。

    展开全文
  • 下载完成后,解压/usr/src下。 2、安装编译内核必须的库: apt-get install nc libssl-dev -y apt-get install build-essential openssl -y apt-get install zlibc minizip -y apt-get install libidn11-dev ...

    KASan(kernel address sanitizer)是一个内核态的动态内存错误检测器,提供了强大的内存错误(out-of-bound and use-after-free)检测功能:

    • 缓冲区溢出 
      ①、堆内存溢出
      ②、栈上内存溢出
      ③、全局区缓存溢出

    • 悬空指针
      ①、使用释放后的堆上内存
      ②、使用返回的栈上内存
      ③、使用退出作用域的变量

    • ...

    由于KASan在内核版本V4.0后才加入,而且内核编译时默认是不启用KASan的,所以需要重新编译配置内核才能启用该功能(gcc版本要求5.0及以上才完全支持)。

    本文实验环境:

    root@ubuntu:~# lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description:    Ubuntu 16.04.6 LTS
    Release:        16.04
    Codename:       xenial
    root@ubuntu:~# 
    root@ubuntu:~# uname -r
    4.4.0-142-generic
    root@ubuntu:~# 

    内容提要:

    ①先将ubuntu16.04的4.4.0内核编译升级到linux-4.4.252版本;

    ②编写一个简单的内核模块看下kasan的强大检测功能。

     

    一、编译内核并配置支持kasan

    1、下载源码

    Linux官网下载内核源码,我这里选择了linux-4.4.252源码

    下载完成后,解压到/usr/src下。

    root@ubuntu:~# cd /usr/src/
    root@ubuntu:/usr/src# wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.4.252.tar.gz
    root@ubuntu:/usr/src# tar xf linux-4.4.252.tar.gz
    root@ubuntu:/usr/src# cd linux-4.4.252

    2、安装编译内核必须的库:

    apt-get install nc libssl-dev build-essential openssl -y
    apt-get install zlibc minizip libidn11-dev libidn11 -y

    3、清理之前内核编译生成及相关配置(为下面全新编译内核做准备)

    root@ubuntu:/usr/src/linux-4.4.252# make mrproper 
      CLEAN   scripts/basic
      CLEAN   scripts/kconfig
      CLEAN   include/config include/generated
    root@ubuntu:/usr/src/linux-4.4.252# make clean
    root@ubuntu:/usr/src/linux-4.4.252# 

     

    4、启动配置菜单

    root@ubuntu:/usr/src/linux-4.4.252# make menuconfig

    依次选择Kernel hacking > Memory Debugging,然后配置内存debug选项,这里我把大部分debug选项都选中了:

    其中,KASan选项中Instrumentation type选inline的:

    配置完成后,exit退出,最后选择yes保存配置项。

    5、开始编译:

    make -j4

    内核编译比较耗时,一般都要半个小时到几个小时(取决于机器性能),为了加快内核编译速度,这里我启用4个线程编译内核,你可以根据自己机器的cpu核数进行调整(lscpu命令可以查看cpu核数)。

    6、模块安装

    root@ubuntu:/usr/src/linux-4.4.252# make modules_install 

    7、安装

    root@ubuntu:/usr/src/linux-4.4.252# make install 
    sh ./arch/x86/boot/install.sh 4.4.252 arch/x86/boot/bzImage \
            System.map "/boot"
    run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.4.252 /boot/vmlinuz-4.4.252
    run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.4.252 /boot/vmlinuz-4.4.252
    update-initramfs: Generating /boot/initrd.img-4.4.252
    run-parts: executing /etc/kernel/postinst.d/zz-update-grub 4.4.252 /boot/vmlinuz-4.4.252
    Generating grub configuration file ...
    Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
    Found linux image: /boot/vmlinuz-4.4.252
    Found initrd image: /boot/initrd.img-4.4.252
    Found linux image: /boot/vmlinuz-4.4.0-171-generic
    Found initrd image: /boot/initrd.img-4.4.0-171-generic
    Found linux image: /boot/vmlinuz-4.4.0-170-generic
    Found initrd image: /boot/initrd.img-4.4.0-170-generic
    Found linux image: /boot/vmlinuz-4.4.0-142-generic
    Found initrd image: /boot/initrd.img-4.4.0-142-generic
    done

    8、修改内核启动顺序

    root@ubuntu:~# grep menuentry /boot/grub/grub.cfg
    if [ x"${feature_menuentry_id}" = xy ]; then
      menuentry_id_option="--id"
      menuentry_id_option=""
    export menuentry_id_option
    menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
    submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.252' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.252-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.252 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.252-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-171-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-171-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-171-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-171-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-170-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-170-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-170-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-170-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-142-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-142-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
            menuentry 'Ubuntu, with Linux 4.4.0-142-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-142-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {

    修改配置:

    root@ubuntu:~# vi /etc/default/grub 

    修改/etc/default/grub文件里GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 4.4.252",红色部分即为上面查找到的新生成的menuentry值。

    然后执行update-grub命令,使改动生效:

    root@ubuntu:~# update-grub
    Generating grub configuration file ...
    Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
    Found linux image: /boot/vmlinuz-4.4.252
    Found initrd image: /boot/initrd.img-4.4.252
    Found linux image: /boot/vmlinuz-4.4.0-171-generic
    Found initrd image: /boot/initrd.img-4.4.0-171-generic
    Found linux image: /boot/vmlinuz-4.4.0-170-generic
    Found initrd image: /boot/initrd.img-4.4.0-170-generic
    Found linux image: /boot/vmlinuz-4.4.0-142-generic
    Found initrd image: /boot/initrd.img-4.4.0-142-generic
    done
    root@ubuntu:~# 

    9、reboot

    重启之后,可以查看验证:

    root@ubuntu:~# uname -r
    4.4.252
    root@ubuntu:~# 
    root@ubuntu:~# grep -nr KASAN /boot/config-4.4.252 
    38:CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000
    7901:CONFIG_HAVE_ARCH_KASAN=y
    7902:CONFIG_KASAN=y
    7903:# CONFIG_KASAN_OUTLINE is not set
    7904:CONFIG_KASAN_INLINE=y
    7905:CONFIG_TEST_KASAN=m

    可以看到,KASan相关的配置都已经启用了。

     

    二、编写测试内核模块

    1、测试代码编写,命名为my_lkm.c文件

    #include <linux/module.h>
    #include <linux/kallsyms.h>
    #include <asm/uaccess.h>
    #include <linux/syscalls.h>
    #include <linux/kernel.h> // __FUNCTION__
    #include <linux/slab.h> // kmalloc kfree
    
    MODULE_LICENSE("GPL");
    
    static int __init test_init(void) 
    { 
        char *ptr; 
        size_t size = 124; 
    
        printk("out-of-bounds to right\n"); 
        ptr = kmalloc(size, GFP_KERNEL); 
        if (!ptr) { 
            printk(KERN_ERR "Allocation failed\n"); 
            return -1; 
        } 
        printk("ptr address: %p\n", ptr); 
    
        ptr[size] = 'x'; 
        printk("ptr[size] address: %p\n", ptr + size); 
    
        kfree(ptr);
        return 0;
    }
     
    
    static void __exit test_exit(void)
    {
        printk("%s removed.\n",__func__);
    }
    
    module_init(test_init);
    module_exit(test_exit);
    

    上述代码中,我们从slab中申请了一个指向124个字节大小的内存空间指针,然后用数组形式访问其第125个字节空间内容,这里故意越界访问,这样kasan会报slab-out-of-bounds错误,见下面系统日志输出。

    2、编写Makefile文件

    vi Makefile

    内容如下:

    ​
    obj-m += my_test_lkm.o
    my_test_lkm-objs := my_lkm.o
    
    EXTRA_CFLAGS += -g -Wall
    
    all:
    	make -C /usr/src/linux-4.4.252/ M=$(PWD) modules
    	 
    clean:
    	make -C /usr/src/linux-4.4.252/ M=$(PWD) clean
    
    ​

    3、编译

    root@ubuntu:/home/test_ko/lkm-test05# make
    make -C /usr/src/linux-4.4.252/ M=/home/test_ko/lkm-test05 modules
    make[1]: Entering directory '/usr/src/linux-4.4.252'
      CC [M]  /home/test_ko/lkm-test05/my_lkm.o
      LD [M]  /home/test_ko/lkm-test05/my_test_lkm.o
      Building modules, stage 2.
      MODPOST 1 modules
      CC      /home/test_ko/lkm-test05/my_test_lkm.mod.o
      LD [M]  /home/test_ko/lkm-test05/my_test_lkm.ko
    make[1]: Leaving directory '/usr/src/linux-4.4.252'
    root@ubuntu:/home/test_ko/lkm-test05# 

    4、insmod my_test_lkm.ko

    5、dmesg -Tw查看系统内核日志:

    可以看到系统内核日志中,KASan报BUG: KASAN: slab-out-of-bounds in test_init+0xa2/0x1000 ,并且下面详细列出了在哪里申请的(Allocated)、哪里释放的(Freed)及整个调用链的详细信息:

    [Tue Jan 19 18:27:29 2021] out-of-bounds to right
    [Tue Jan 19 18:27:29 2021] ptr address: ffff8800badbd910
    [Tue Jan 19 18:27:29 2021] ==================================================================
    [Tue Jan 19 18:27:29 2021] BUG: KASAN: slab-out-of-bounds in test_init+0xa2/0x1000 [my_test_lkm] at addr ffff8800badbd98c
    [Tue Jan 19 18:27:29 2021] Write of size 1 by task insmod/100870
    [Tue Jan 19 18:27:29 2021] =============================================================================
    [Tue Jan 19 18:27:29 2021] BUG kmalloc-128 (Tainted: G    B      OE  ): kasan: bad access detected
    [Tue Jan 19 18:27:29 2021] -----------------------------------------------------------------------------
    
    [Tue Jan 19 18:27:29 2021] INFO: Allocated in test_init+0x4c/0x1000 [my_test_lkm] age=4 cpu=0 pid=100870
    [Tue Jan 19 18:27:29 2021]      ___slab_alloc+0x4d9/0x550
    [Tue Jan 19 18:27:29 2021]      __slab_alloc+0x20/0x40
    [Tue Jan 19 18:27:29 2021]      kmem_cache_alloc_trace+0x24c/0x2e0
    [Tue Jan 19 18:27:29 2021]      test_init+0x4c/0x1000 [my_test_lkm]
    [Tue Jan 19 18:27:29 2021]      do_one_initcall+0x143/0x300
    [Tue Jan 19 18:27:29 2021]      do_init_module+0x1d9/0x4de
    [Tue Jan 19 18:27:29 2021]      load_module+0x6a4f/0xa160
    [Tue Jan 19 18:27:29 2021]      SYSC_finit_module+0x126/0x160
    [Tue Jan 19 18:27:29 2021]      SyS_finit_module+0xe/0x10
    [Tue Jan 19 18:27:29 2021]      entry_SYSCALL_64_fastpath+0x22/0x9e
    [Tue Jan 19 18:27:29 2021] INFO: Freed in load_elf_binary+0x220/0x4480 age=14729 cpu=0 pid=100293
    [Tue Jan 19 18:27:29 2021]      __slab_free+0x1bc/0x300
    [Tue Jan 19 18:27:29 2021]      kfree+0x106/0x1e0
    [Tue Jan 19 18:27:29 2021]      load_elf_binary+0x220/0x4480
    [Tue Jan 19 18:27:29 2021]      search_binary_handler+0x156/0x430
    [Tue Jan 19 18:27:29 2021]      do_execveat_common.isra.31+0x1025/0x1ae0
    [Tue Jan 19 18:27:29 2021]      SyS_execve+0x3a/0x50
    [Tue Jan 19 18:27:29 2021]      return_from_execve+0x0/0x23
    [Tue Jan 19 18:27:29 2021] INFO: Slab 0xffffea0002eb6e00 objects=71 used=30 fp=0xffff8800badbb738 flags=0x1ffff8000004080
    [Tue Jan 19 18:27:29 2021] INFO: Object 0xffff8800badbd910 @offset=22800 fp=0xffff8800badb9728
    
    [Tue Jan 19 18:27:29 2021] Bytes b4 ffff8800badbd900: 19 37 d1 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a  .7......ZZZZZZZZ
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd910: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd920: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd930: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd940: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd950: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd960: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd970: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    [Tue Jan 19 18:27:29 2021] Object ffff8800badbd980: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
    [Tue Jan 19 18:27:29 2021] Redzone ffff8800badbd990: cc cc cc cc cc cc cc cc                          ........
    [Tue Jan 19 18:27:29 2021] Padding ffff8800badbdad0: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
    [Tue Jan 19 18:27:29 2021] CPU: 0 PID: 100870 Comm: insmod Tainted: G    B      OE   4.4.252 #1
    [Tue Jan 19 18:27:29 2021] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/29/2019
    [Tue Jan 19 18:27:29 2021]  0000000000000000 41692362580668d4 ffff8800a1287898 ffffffff82988c2f
    [Tue Jan 19 18:27:29 2021]  ffff88011840f580 ffff8800badbd910 ffff8800a12878c8 ffffffff81585cc9
    [Tue Jan 19 18:27:29 2021]  ffff88011840f580 ffffea0002eb6e00 ffff8800badbd910 0000000000000001
    [Tue Jan 19 18:27:29 2021] Call Trace:
    [Tue Jan 19 18:27:29 2021]  [<ffffffff82988c2f>] dump_stack+0x6d/0x8b
    [Tue Jan 19 18:27:29 2021]  [<ffffffff81585cc9>] print_trailer+0xf9/0x150
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158cda4>] object_err+0x34/0x40
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158f5ad>] kasan_report.part.2+0x21d/0x520
    [Tue Jan 19 18:27:29 2021]  [<ffffffffc0a500a2>] ? test_init+0xa2/0x1000 [my_test_lkm]
    [Tue Jan 19 18:27:29 2021]  [<ffffffff81589fb0>] ? kmem_cache_alloc_trace+0x120/0x2e0
    [Tue Jan 19 18:27:29 2021]  [<ffffffffc0a50000>] ? 0xffffffffc0a50000
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158f9d1>] __asan_report_store1_noabort+0x31/0x40
    [Tue Jan 19 18:27:29 2021]  [<ffffffffc0a500a2>] test_init+0xa2/0x1000 [my_test_lkm]
    [Tue Jan 19 18:27:29 2021]  [<ffffffff810021b3>] do_one_initcall+0x143/0x300
    [Tue Jan 19 18:27:29 2021]  [<ffffffff81002070>] ? try_to_run_init_process+0x40/0x40
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158ed1e>] ? kasan_kmalloc+0x5e/0x70
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
    [Tue Jan 19 18:27:29 2021]  [<ffffffff8158edb7>] ? __asan_register_globals+0x87/0xa0
    [Tue Jan 19 18:27:29 2021]  [<ffffffff82985bf4>] do_init_module+0x1d9/0x4de
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812fc3df>] load_module+0x6a4f/0xa160
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812f0c00>] ? m_show+0x4b0/0x4b0
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812f5990>] ? module_frob_arch_sections+0x20/0x20
    [Tue Jan 19 18:27:29 2021]  [<ffffffff815eeedb>] ? kernel_read+0xeb/0x1a0
    [Tue Jan 19 18:27:29 2021]  [<ffffffff815eedf0>] ? open_exec+0x50/0x50
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812f10dd>] ? copy_module_from_fd.isra.50+0x1dd/0x2f0
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812ffe26>] SYSC_finit_module+0x126/0x160
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812ffd00>] ? SYSC_init_module+0x210/0x210
    [Tue Jan 19 18:27:29 2021]  [<ffffffff812ffe7e>] SyS_finit_module+0xe/0x10
    [Tue Jan 19 18:27:29 2021]  [<ffffffff829ab5e5>] entry_SYSCALL_64_fastpath+0x22/0x9e
    [Tue Jan 19 18:27:29 2021] Memory state around the buggy address:
    [Tue Jan 19 18:27:29 2021]  ffff8800badbd880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
    [Tue Jan 19 18:27:29 2021]  ffff8800badbd900: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    [Tue Jan 19 18:27:29 2021] >ffff8800badbd980: 00 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
    [Tue Jan 19 18:27:29 2021]                       ^
    [Tue Jan 19 18:27:29 2021]  ffff8800badbda00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
    [Tue Jan 19 18:27:29 2021]  ffff8800badbda80: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
    [Tue Jan 19 18:27:29 2021] ==================================================================
    [Tue Jan 19 18:27:29 2021] ptr[size] address: ffff8800badbd98c

    本文已同步至我的微信公众号这里

    欢迎关注我的微信公众号大胖聊编程,也可以加好友一起交流学习。

     

     

    参考链接:

    https://www.kernel.org/doc/html/latest/dev-tools/kasan.html

     

     

    展开全文
  • 比如d3d错误使用时造成的内存泄露 m_pd3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer); 如果pBackBuffer用完后不release,就会有内存泄露,但是vc的内存检测不会告诉你这里有内存泄露
  • C++中内存错误通常属于运行时错误,只有在程序运行时才能发现,编译器无法自动检测到内存错误。多数情况下是程序逻辑或者参数存在某些错误。下面总结一下C++常见的内存错误: 内存泄露 内存泄露是指应用程序未释放...
  • 内存泄漏检测内存越界检测

    千次阅读 2019-05-17 14:13:39
    本程序为内存泄漏和内存越界检测。本文及程序为原创,转发请标注littlezls原创。 欢迎大家相互交流学习。 1. 说明 作为一个编程人员,或许你会需要下面三个问题: 1.由于代码量大,项目复杂, 用系统函数malloc,...
  • 它的使用历史可以追溯计算机编程的远古时代(30多年以前)。经过这么多年的发展,它不但能够监测出许多语法逻辑上的隐患,而且也能够有效地帮 你提出许多程序在空间利用、运行效率上的改进点,在很多专业级的软件...
  • 首先,官网下载valgrind源码: http://valgrind.org/downloads/current.html 对源码进行编译。 我用的是mac系统,对源码解压后,在源码目录下创建配置脚本 export NDKROOT=/android-ndk-r9d export HWKIND=...
  • 检测到问题时,该应用程序将被中断,您可以对其进行调试。 注意:您可以在Linux上本地安装和运行Memcheck。您可以从任何开发计算机在远程主机或设备上运行它。在Windows上,可以使用Heob堆观察
  • 详细说明了如何在ROOTED设备上自动检测内存管理,线程错误和配置Android应用程序的说明。 连接Android设备 $ adb connect [device_ip] 转Android Valgrind的文件夹 $ cd [android-valgrind] 在设备上安装...
  • MemTest内存检测工具

    2017-10-12 15:20:52
    是个比较少见的内存检测工具,它不但可以彻底的检测出内存的稳定度,还可同时测试记忆的储存与检索资料的能力,让你可以确实掌控到目前你机器上正在使用的内存到底可不可信赖 ...检测到 400%的间歇性问题测试。
  • valgrind 内存泄露检测

    2020-09-25 14:18:17
    Valgrind工具可以自动检测许多内存管理和线程错误,并详细分析您的程序。 Valgrind可以执行非常详细的分析,以帮助找到程序中的瓶颈。 Valgrind可以自动检测许多内存管理和线程错误。这让你有信心你的程序没有许多...
  • (provider: 共享内存提供程序, error: 1 - 执行读/写操作期间检测到 I/O 错误。) ,提示过后,重新连接,可以正常创建数据库(Use mater)) 请问是什么原因?猜想是数据库的资源未被释放! ...
  • valgrind检测内存泄露

    2017-08-29 16:50:12
    上次使用了electric-fence来检测内存泄露,发现程序异常的卡,所以改用valgrind apt install valgrind 安装 valgrind --tool=memcheck --leak-check=full 你的程序 注意:--leak-check=full 如果不加有可能会...
  • 内存泄漏和检测方式

    2020-09-16 15:30:15
    最难捉摸也最难检测到错误之一是内存泄漏,即未能正确释放以前分配的内存的 bug。 只发生一次的小的内存泄漏可能不会被注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种征兆:从性能不良(并且...
  • vc内存泄露检测

    2011-09-15 08:16:47
    偶尔发生的少量内存泄漏可能不会引起我们的注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种各样的征兆:从性能不良(并且逐渐降低)到内存完全耗尽。更糟的是,泄漏的程序可能会用掉太多内存,导致...
  • valgrind内存检测工具

    2018-06-13 20:02:00
    valgrind那点事 ---------------------------------------内存检测工具 valgrind要使用此工具,可以使用--tool=memcheck 在...它可以检测到C和C ++程序中常见的以下问题。访问内存不应该,例如溢出和溢出堆块,溢...
  • C/C++内存泄漏及检测

    2020-12-22 17:01:53
     难捉摸也难检测到错误之一是内存泄漏,即未能正确释放以前分配的内存的 bug。 只发生一次的小的内存泄漏可能不会被注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种征兆:从性能不良(并且逐渐...
  • 内存检测2.1.1.apk

    2021-06-02 17:15:25
    适用于安卓新硬件设备的ram和emmc检测的工具,实时记录每一次的结果文件,错误日志,可以进行长期性测试
  • 开发中时常需要在生产和测试环境查看log日志, 就索性写了一个python脚本来检测错误和异常然后写页面,通过钉钉机器人把页面地址发送来提醒,但是居然被拦了, 一大堆不安全不合理没必要的理由面前 我也就放弃了....
  • 在航天领域中,安全关键的大型实时软件系统往往直接影响任务成败,一般难以全面检测、分析或避免内存泄漏等常见内存错误。定义了实时软件的12种典型内存故障模式,提出了一种基于C++代码插装的实时软件内存错误快速...
  • PHP内存泄漏检测方法

    千次阅读 2015-12-28 17:41:41
    一 PHP内置内存泄漏探测: PHP本身有自己的内存管理,在编译时,增加编译选项--enable-debug 以及相应扩展编译时加上 ./...注意:这个方法只能检测到使用了Zend内存管理的情况,对于直接使用malloc/free来申请内
  • 忘记delete内存。容易造成内存泄漏,程序运行很长时间后,等到内存耗尽后才出现错误。...通过释放内存后将指针置为空,有时可以检测到这种错误 同一块内存释放两次。两个指针指向同一块内存空间。。 ...
  • 内存检测工具memtest86+

    2012-10-25 10:11:55
    Memtest86一检测到缺陷位,就会在屏幕底部显示一条出错消息,但是测试还将继续下去。如果完成几遍测试后,没有任何错误信息,那么我们可以确定内存是稳定可靠的。如果检测出现问题,你可以试着降低BIOS中内存参数的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 934
精华内容 373
关键字:

检测到内存错误