调试大型应用程序的技巧

嗨,我是Vaishnavi Sannidhanam,Phoenix编译器后端团队的测试负责人。Phoenix是一个平台和分析框架。有关凤凰城的更多信息,请收听我们的建筑师安迪·艾尔斯在9频道的演讲 https://channel9.msdn.com/Showpost.aspx?postid=396461 .

null

我们的编译器测试用例包括编译大型应用程序,如Windows、SQL、Office、visualstudio等。 有时,事情并不像预期的那样进行,我们在编译器或我们正在编译的产品中遇到错误。 在这样的情况下,通过附加一个调试器来调试普通的旧方法是非常困难的,因为我们不知道我们正在编译的大部分代码库,因此无法单步执行逻辑流。 我想和大家分享两种应对这些挑战的方法。

运行时错误检查

为什么这项技术有用?

这种技术对于在编译时发现可能的运行时问题非常有用。  即使没有尝试调试的异常故障,启用此选项也很有用。

技术

用RTC运行时错误检查编译代码。这可以帮助您找到发生意外数据丢失的位置、查找未初始化变量的用法、检测溢出和不足、堆栈指针损坏和堆栈损坏。

你可以在网站上找到更多信息 http://msdn2.microsoft.com/en-us/library/8wtf2dfz(对80).aspx

假设

此技术假定您没有将/RTC用于优化(发布)版本,因为/RTC不能用于这些版本。

二进制搜索

为什么这项技术有用?

当自动测试失败时,这种技术非常方便。您可以自动执行搜索过程,以识别和区分错误的部分,从而节省开发人员和测试人员的时间。

技术

1. 隔离为二进制: 将二进制文件(DLL)混合在上一个已知的良好版本和错误版本之间,执行二进制搜索,然后重新运行测试。不断重复,直到你已经分离出坏的二进制文件。

2. 隔离到目标: 一旦确定了损坏的二进制文件,就在不使用LTCG(链接时代码生成或不使用/GL开关)的情况下编译各种obj,然后在好的构建和坏的构建之间混合和匹配obj,以找到导致问题的obj文件。

3. 错误区域: 现在您已经知道了错误的obj,如果您试图在调试版本中出现错误,那么您可以区分工作obj版本的源代码和损坏的版本。

另一方面,如果这种情况只发生在优化打开时,即错误只存在于零售版本中,那么可能有三个原因:打开优化会导致错误代码生成(编译器问题),打开优化会暴露应用程序问题(如缓冲区溢出或未初始化变量–应用程序错误),或者应用程序所做的假设在存在优化的情况下是错误的,编译器进行这种转换是完全合法的(应用程序错误)。

下面是一些我们经常看到的应用程序错误的例子,这些错误会在优化过程中暴露出来

i=i+++i++;

语句后面的“i”的值可以是2、3或4,并且所有这些值都有效,因为此类表达式的行为未定义。

*p=foo(p)

如果在上述情况下foo改变了p,那么行为同样是未定义的(因为可以在调用foo之前对LHS进行评估,反之亦然),并且它可以在优化和未优化的构建之间变化。

p

根据C标准,这可以优化为0

在多线程应用程序中缺少volatile限定符是另一个只发生在优化构建中而不发生在未优化构建中的bug的例子。这是因为编译器不会维护对优化构建中非易失性对象的引用的顺序(http://msdn2.microsoft.com/en-us/library/12a04hfd(对80).aspx)

为了帮助调试这段代码,通过使用#pragma optimize(“,off”)关闭函数/函数集的所有优化并重新运行测试,在该obj中的函数之间进行二进制搜索非常有帮助。一旦确定了导致问题的函数,就可以检查该函数的源代码在好版本和坏版本之间的差异。  更多信息请访问 http://msdn2.microsoft.com/en-us/library/chh3fb0k(对80).aspx

假设

此技术假设您有一个好的构建,可以将其用作对坏的构建执行二进制搜索的引用。  好的构建和坏的构建之间不应该有任何API更改。

我希望你喜欢这篇文章,它可以帮助你的调试工作。

谢谢, Vaishnavi Sannidhanam公司 试验引线 Visual C++团队

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享