特别感谢亚伦·戈伦斯坦写了这篇博文。
地址消毒剂(ASan)是 一般可用 从最近发布的VisualStudio2019版本16.9开始。我们已经准备好了 展示 即使是像EASTL这样的产品级代码也很容易发现bug。这里我将分享一个例子,说明它是如何在MSVC编译器中发现一个真正的bug的。
这个想法很简单:ASan发现bug,我们总是对在编译器中发现bug感兴趣。就像您可以在项目中启用ASan并运行测试一样,我们一直在项目(编译器)中启用ASan并在测试中运行它。果然,这发现了虫子。
用ASan构建二进制文件
在我们的构建系统中很容易启用ASan。我们已经记录了如何在 常见的 建造 情节。在我们的情况下,我补充说 /fsanitize=address
对于构建的cl.exe命令行,我们的旧的、不断发展的构建系统需要额外的手动步骤来指定 延伸 图书馆还活着。
就这些!我现在能够构建我的二进制文件c2.dll,“就像普通的一样”,但是现在它有很多优秀的ASan工具来帮助查找bug。我已经准备好运行我们的内环测试套件,看看是否出现了什么问题。
找到窃听器
我们的内部测试循环是大约4000个独立的C++文件,包含真实世界代码、合成测试、基准测试和回归测试的混合。我们有一个自制的测试运行程序,只能从命令行访问。运行它,我们几乎通过,但正好击中1失败。我查看了我们的日志文件,看到了特征跟踪:
我想强调两点:
- 报告的错误是“堆栈缓冲区下溢”:这是一个 堆栈 ASan能够同时发现堆栈和堆问题。
- 注意行“thread T3的堆栈”。这表明,还有一个T1和T2(以及更多):c2.dll并行执行许多线程。ASan可以像那样处理多个线程没有问题!
最重要的是: 阿桑从来没有假阳性 . 我发现的这个痕迹肯定是个bug,所以我已经知道我找到了要修复的东西。
幸运的是,触发输入是一个文件。我可以很容易地重复命令,复制的错误手动。要说清楚,在这一点上,我需要做的就是解决这个问题:
我已经截断了输出,但是终端包含完整的ASan命令行诊断。我可以使用这些信息(从上面可以看到的堆栈跟踪开始)来调查这个问题。但是,我喜欢在完整的IDE和调试体验中检查这些。使用此命令行,我可以复制ASan问题,但将其附加到调试器:
启动二进制文件的调试器附加版本时,我看到:
IDE能够提供丰富的- 以交互方式 -关于发生了什么的信息 那一刻 检测到内存冲突。您可以看到ASan问题被报告为异常,这使我找到了正确的行号,以及我熟悉的调试器调用堆栈和其他一切。输出窗口对于那些习惯它的人仍然是可用的。
猜猜虫子可能藏在哪里?
提示: sz
“可能”代表“大小”。观察并回忆ASan如何报告“堆栈缓冲区” 下溢 ”.
修复错误
检查 sz
说得很清楚: MscIsFloatOrVectorConstant
返回常量的大小 如果找到了 ,否则为0。在这个错误的例子中,它返回0,我们在函数local struct中下溢数组字段 vval
. 修复方法同样简单:在文件的其余部分中遵循习惯用法,我们只需在第16828行之前添加一个检查。
这个特定的bug不太可能“在野外”出现:堆栈需要以正确的方式具有垃圾值(以传递第16831行的条件)。但是,从理论上讲,这个bug和更一般的bug可能会导致代码中的不适当优化。这是编译器可能遇到的最糟糕的bug之一:无声的坏codegen。我很高兴压扁了这个。我也很高兴能够与您分享ASan如何轻松地进行错误修复。
结论
我们通常不会写关于修复编译器中的bug的博客文章,但真正的故事是ASan如何轻松有效地帮助发现和修复bug:
- 我们定制的、命令行驱动的构建系统只需要几行更改就可以将构建与ASan选项集成。
- 一旦构建,测试我们的二进制文件是无缝的:我运行了典型的内部开发循环测试套件。
- 一旦发现问题,重复IDE调试器中的步骤同样是天衣无缝的,直接将我指向要检查的源代码行。
- 在更复杂的情况下, 考虑保存转储文件的功能 !
- 精确的源代码行,再加上ASan描述问题的能力(一个堆栈) 下溢 ),使调查快捷方便。不需要长时间的工作,也不需要高明的洞察力:当然,我仍然需要确认并实际解决这个问题,但与传统的错误修复相比,很多调查都是短暂的。
我希望这个故事能帮助说明ASan的速度、效率和简单性。此外,最令我信服的是:阿桑发现了一个记忆障碍 那还没有表现为不良行为 在我们的节目里。它 能够 显然,但在这里,我们能够确定下来,压扁它没有一个昂贵的,更间接的调查,希望没有它曾经影响过我们的客户!
试用Windows的AddressSanitizer
要开始这种体验,请查看我们的 MSVC和Visual Studio的AddressSanitizer文档 以及我们的公告博客: 地址MSVC消毒剂现在普遍可用 .
MSVC的ASan是根据像您这样的开发人员的反馈完成的。如果您对未定义的行为、内存、线程或其他消毒剂的未来有任何建议,请将其作为 开发商社区建议 ! 如果您怀疑您遇到了问题或bug,请不要犹豫 在开发者社区开罚单 !