【Asan】新鲜货:使用ASan检测内存越界问题

新特性出炉

近日,一个新的特性被添加到了MSVC工具集中,这个就是Windows C++开发者梦寐以求的AddressSanitizer(ASan)。为什么这么说:GCC早在4.8就可以支持ASan了,是时候轮到咱大Windows开发者了吧?

啥是ASan?

ASan是一个用来快速检测内存错误的工具,它可以找到程序中出现的内存访问违规问题,例如使用已经释放了的内存,内存指针越界访问等。一直以来,ASan支持一直都是开发者社区中呼声较高的一项特性,今天,我们可以说,我们可以在Windows开发平台中使用上ASan了。

在微软,我们相信:我们的开发者应该能根据自己的需要来选择不同的开发工具,我们也非常高兴和LLVM团队合作,将他们的一些十分好用的工具集成到Visual Studio中。之前,我们也引入了一些工具特性,例如clang-format,以及最近更新的clang-tidy。MSVC中对ASan的支持将会在我们的第二个VS2019 v16.4预览版中和大家见面。

为了在Windows和MSVC中支持ASan,我们做了以下的工作:

=> 更新了ASan运行时库,使其能更加好的在Windows平台工作=> MSVC编译器可以使用ASan进行二进制Profiling=> CMake和MSBuild也进行了更新来支持ASan=> VS调试器可以在Windows二进制中检测到ASan错误=> ASan可以在VS安装程序中的C++ Develop workload中被安装

当你调试一个已经启用了ASan的程序时,Visual Studio中的Exception Helper可以显示一个内存错误,并退出程序运行。同时,你可以可以在输出窗口看到有关的错误信息。

在Windows中安装ASan

在默认情况下,ASan已经包含在了C++ Desktop workload中,注意这个仅在全新安装时才会可见。如果你是从VS2019的一个旧版本上升级,则需要在升级完成之后来启用ASan支持。如下图所示:

在上图中,你可以从VS安装程序中修改已经安装的工具。请注意,如果你运行的是更新版本的Visual Studio但是还未启用ASan,则当你运行程序时,将会出现如下的错误:

LNK 1356 – cannot find library ‘clang_rt.asan_dynamic-i386.lib’

为Windows MSBuild工程启用ASan

在MSBuild工程中,你可以通过点击工程属性下面的C/C++ > 常规,启用[Enable Address Sanitizer(Experimental)]来启用ASan。同时,这个方法也适用于MSBuild Linux工程。

请注意:当前ASan只能在x86二进制下工作,在将来的版本中,会支持更多的架构。

为Windows CMake工程启用ASan

为了在目标平台为Windows的CMake工程启用ASan,可以按照如下的方法:

  1. 在IDE中打开配置下拉列表,点击[Manage Configurations],这回打开CMake工程的配置界面,在这个配置界面的修改会保存到CMakeSettings.json文件中。

  2. 点击[Edit JSON]链接,这将会切换到原始版本的json文本内容。

  3. 在[x86-Release]配置节点下,添加属性:”addressSanitizerEnabled”: true

你会看到会出现一个警告信息标识:Property name is not allowed by the schema.

但是请不用担心,这个是一个小Bug,会很快被修复。

下面是一个修改之后的CMakeSettings.json文件的部分截图:

在将来的版本更新中,我们将想办法进一步的简化在CMake工程中启用ASan的步骤,敬请期待。

ASan运行时开发

为了增强ASan在Windows平台上的体验,我们决定为LLVM compiler-rt 工程贡献代码,并重用这个工程中的ASan运行时库的实现。我们对这个工程的贡献包括一些BugFix和优化的HeapAlloc , RtlAllocateHeap , GlobalAlloc , 和LocalAlloc拦截代码,并使用了他们的Free , ReAllocate , 和Size等函数实现。开发者可以通过添加ASAN_OPTIONS环境变量来在Clang工具集或者MSVC工具集中启用这些特性,如下图所示:

为支持ASan,MSVC中做了如下的修改

为了支持ASan这一特性,我们修改了c1.dll和c2.dll,使其在编译期在目标程序中加入instrumentaion代码。对于一个32位的地址空间,大约会有200MB的内存被分配来隐射整地址空间。当一个内存被分配,在地址空间中有个标志位会被修改来表示这个内存分配有效并可访问。当这个内存被释放或者变量离开作用域时,地址空间里对应的标志位会被修改,来映射这个内存分配变得不再有效。

潜在危险的内存访问会在地址空间中被重复检测来验证运行时访问时的有效性。当发生内存访问违规时,错误信息会被输出至stderr或者以一个异常的方式来报告给开发者。在地址空间中,当访问一个内存区域时,其内存数据会首先被检查。ASan的算法可以报告内存访问错误的具体位置以及错误的原因。

这意味着,如果一个程序被MSVC+ASan编译,则这个程序会添加一个对clang_rt.asan的依赖。每个库都有特殊的使用场景,如果你的程序比较复杂则对应的链接过程也会比较复杂。

从控制台中编译ASan

在控制台中,你可以手动的链接ASan库。对于x86平台二进制文件,有如下的库需要被链接:

=> clang_rt.asan-i386.lib – static runtime compatible with /MT CRT.=> clang_rt.asan_cxx-i386.lib -static runtime component which adds support for new and delete, also compatible with /MT CRT.=> clang_rt.asan_dynamic-i386.lib – dynamic import library, compatible with /MD CRT.=> clang_rt.asan_dynamic-i386.dll – dynamic runtime DLL, compatible with /MD.=> clang_rt.asan_dynamic_runtime_thunk-i386.lib – dynamic library to import and intercept some /MD CRT functions manually.=> clang_rt.asan_dll_thunk-i386.lib – import library which allows an ASAN instrumented DLL to use the static ASan library which is linked into the main executable. Compatible with /MT CRT.

当你选择了合适的ASan运行时库,则应添加命令行/wholearchive:到链接参数中并添加指定的库文件。clang_rt.asan_dynamic_i386.dll这个文件将不会安装到System32目录,因此当运行你的程序的时候,需要确保ASan运行时库可以被加载器找到。

以下是一些额外的建议

=> 编译单个静态执行文件: 链接静态运行库(asan-i386.lib)和对应的cxx库。=> 以/MT运行时库链接可执行文件同时使用ASan DLL: 可执行文件将链接asan-i386.lib并且DLL需要clang_rt.asan_dll_thunk-i386.lib。这可以使DLL使用运行时链接到主程序中并且避免潜在的Shadow memory的冲突问题。=> 以/MD进行动态编译:所有的EXE和DLL文件必须链接asan_dynamic-i386.lib和clang_rt.asan_dynamic_runtime_thunk-i386.lib。在运行时,这些库文件将会引用对应的clang_rt.asan_dynamic-i386.dll文件。

另外请注意:ASan运行时库将会在执行期对内存管理函数进行拦截并将函数调用重定向至ASan的对应的封装函数。当运行时环境和库编写时的目标环境不一样的时候,这可能会造成一些不稳定的问题。

总结

通过使用ASan,可以有效的检测一些潜在的内存访问问题,真是我们C++程序开发者的福音啊。

参考链接:
新鲜货:使用ASan检测内存越界问题

【Asan】新鲜货:使用ASan检测内存越界问题相关推荐

  1. Asan快速定位内存越界、内存泄漏

    [摘要]asan检测内存漏洞(堆踩内存.栈越界.堆越界.使用未初始化的内存等)和内存泄漏,如果不使用工具,我们直接去排查,那成本将是巨大的,我所在公司属于嵌入式设备制造商,曾遇到过一个野指针问题,但是 ...

  2. 使用asan检测内存泄漏、堆栈溢出等问题

    一.使用过程 操作过程参考:链接 缘起:程序在移动端崩溃,mac端复现不了,于是在写个崩溃位置函数的调用demo,使用ASAN工具进行排查. 验证过程 1.代码 main.cpp #include & ...

  3. 动态检测内存错误利器ASan

    ASan,即Address Sanitizer,是一个适用于c/c++程序的动态内存错误检测器,它由一个编译器检测模块(LLVM pass)和一个替换malloc函数的运行时库组成,在性能及检测内存错 ...

  4. ASAN 检测内存错误 debug

    ASAN 检测内存错误 debug 编译时添加选项 -fsanitize=address -fno-omit-frame-pointer 或在封装器中处理-c时添加编译选项,在链接阶段添加-lasan ...

  5. c/c++动态检测内存错误利器 - ASan

    ASan,即Address Sanitizer,是一个适用于c/c++的动态内存错误检测器,它由一个编译器检测模块(LLVM pass)和一个替换malloc函数的运行时库组成,在性能及检测内存错误方 ...

  6. 【内存】内存检测工具sanitizer[内存泄漏、内存越界] VS valgrind

    简介 Sanitizers是谷歌发起的开源工具集,包括了AddressSanitizer, MemorySanitizer, ThreadSanitizer, LeakSanitizer,Saniti ...

  7. Linux mcheck机制检测内存溢出、内存越界

    更多源码:https://github.com/Rtoax/test/tree/master/c/glibc/mcheck #include <stdio.h> #include < ...

  8. 转载浅谈MFC内存泄露检测及内存越界访问保护机制

    2019独角兽企业重金招聘Python工程师标准>>> 本文所有代码均在VC2008下编译.调试.如果您使用的编译器不同,结果可能会有差别,但本文讲述的原理对于大部分编译器应该是相似 ...

  9. linux踩内存内存越界,Linux如何调试内存泄漏?超牛干货奉献给你(代码全)

    内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存 ...

  10. Linux快速定位内存泄露和内存越界

    在日常开发中,遇到段错误是很常见的事,其中一种情况 Out of memory(OOM),内存泄露问题一般不好查找,但是可以借助工具来快速定位. 这里介绍的工具是valgrind,这个工具在build ...

最新文章

  1. 关于第三方IOS的checkBox框架的使用
  2. 返回当前文档的文档的url
  3. Nginx could not build the server
  4. UNITY中使用不安全代码的相关设置
  5. [转载]EXT核心API详解(一)-Ext
  6. opencv生成日志_OpenCV-Utils学习日志:VideoCapture使用样例
  7. soliworks三维机柜布局(三)绘制电气线路图
  8. 对于三极管饱和状态的一些浅见——与网友的讨论贴
  9. POI实现word转html(带图片),实现word在线预览
  10. Python中一个非常高效的json对比库--deepdiff
  11. Sun jdk、Openjdk、Icedtea jdk关系
  12. 国内IT界女神程序员!和她们一样漂亮的还有谁?
  13. Fastlane使用说明
  14. 浅谈四层交换机技术原理
  15. 【云原生kubernetes】coredns解析集群外部域名
  16. 统计图表插件Chart.js(前端常用图表)
  17. element ui框架(准备)
  18. 计算机网络学网络制图吗,计算机网络论文发表简述计算机设计制图教学改革
  19. TypeError: Failed to execute ‘setItem‘ on ‘Storage‘: 2 arguments requir
  20. 用于游戏开发和其他目的的光线投射教程

热门文章

  1. IDEA使用破解补丁激活
  2. github如何开启两步验证
  3. 机体坐标系的角速度分量
  4. Echarts示例大全 Demo合集网站
  5. An exception was thrown while activating xxxxController
  6. 上古八大姓氏,来看看有没有你的姓氏?
  7. elementui不生效
  8. 行满秩矩阵为何变成增广矩阵还为满秩
  9. 第三方统计分析埋点工具对比,神策、Ptmind、GrowingIO、国双,还有谷歌分析,谁更好?...
  10. rails中引入god