处理可能包含未定义行为的项目
Posted
技术标签:
【中文标题】处理可能包含未定义行为的项目【英文标题】:Deal with project which may contain undefined behaviour 【发布时间】:2016-01-29 06:37:11 【问题描述】:我想建议在这种情况下如何进行。 想象一下,我有一个运行良好的大型 C++ 项目。
我怀疑这段代码中可能有一些 UB(因为在同一作者编写的不同项目中我发现了 UB)。
现在,假设我需要为这个项目添加新功能。 我害怕是因为:
如果我用新的编译器重新编译,如果代码中已经是 UB,这会增加发生 UB 的风险。 (例如,新编译器可能无法与旧编译器兼容的 UB 兼容)。在这个大型项目中通过肉眼检查消除所有 UB 是否现实(在我开始添加新功能之前)?
如果不是,那么我至少应该使用相同版本的编译器进行编译,对吧? (如果有 UB,以减少出现问题的机会)。
项目是在 Visual Studio 中完成的,所以我不知道是否有目标文件,在这种情况下,我可以保持目标文件不变,只修改需要添加内容的文件中的部分 - 从而再次最大限度地降低 UB 的风险.
在这种情况下采取什么行动?我认为这可能是很常见的情况。
我喜欢建议在添加新代码之前使用新编译器测试项目,但即便如此 - 我们知道测试可能不会显示 UB,不是吗?
【问题讨论】:
不要害怕遇到错误。最好找到它们,而不是在您不知情的情况下将它们包含在代码中。 几乎任何大型项目都必然包含一些 UB,当切换到新的编译器时,通常会出现一些潜在的错误。我不认为你可以做任何魔法来避免它。只需编写好的测试并聘请好的测试人员。 @user200312 正如其他答案所说,最新的编译器是一个非常好的建议。此外,最新的 VS 在分析器中有一些非常创新的功能。 用新编译器编译并运行一些测试在对代码进行任何更改之前。如果它有效,您可以继续,确保新编译器不会造成灾难;如果它出了问题,这不是你的错,并且你有证据证明旧代码有错误。 @user200312 您知道在现实世界中,如果您没有 100% 无错误的程序也没关系,对吧?那不是因为错误是可以的,而是因为你永远不可能有一个 100% 没有错误的程序。您所能做的就是尽最大努力检测它们。这就是测试和分析仪的用途。当您检测到错误时,您会修复它。没有其他方法可以解决它。有时您会在产品发货后检测到错误。这就是更新和错误修复的目的。 【参考方案1】:按顺序,我会:
-
使用
-Wall
(Windows 用户为/W4
)编译并修复错误。
如果还没有测试,请编写测试。
使用valgrind
等工具检测并修复问题。
研究正在使用的同步原语,并尽可能使用现代范例。
记录代码并遵守样式指南。
我不会试图通过保留目标文件来避免问题。这是一个噩梦般的维护问题。
【讨论】:
OP使用Visual Studio,相当于gcc的-Wall是/W4 你抓住了我。我没有任何 Microsoft 产品。【参考方案2】:未定义行为 = 错误
不可能证明一个项目没有错误。即使是最好的程序员也会制造错误。即使是最好的代码审查也无法消除项目中的所有错误。不,通过代码检查或任何其他方式消除某个规模项目中的所有 UB 是不现实的。您最好的选择是审查代码并尽可能多地消除。
改变您对 UB(错误)的看法:如果您在重新设计过程中遇到错误,这是一件好事!您处于删除一个 UB 的最佳位置。
不要因为害怕 UB 而保留旧的编译器。使用可用的最新最好的编译器重新编译项目。编译器也可能有错误。较新的编译器将生成更好、更健壮的代码。较新的编译器会产生更好的警告。使用所有可能的警告-Wall
。
消除编译器产生的所有警告。每一个警告都是有原因的,它突出了一个问题。如今,“误报”的可能性非常小。甚至对于 MSVC 也是如此(我不是在谈论像 VC 2005 之前那样真正的旧编译器)
使用静态代码检查器 (Cppcheck)。它可以指出代码的常见问题。
使用custom rule set 作为代码检查器。它将帮助您使代码达到某种标准。
如果可能,请使用其他编译器(GCC、Clang)编译项目,以获取这些编译器的警告。
不要链接到旧的目标文件。这会产生比你认为它避免的更多的问题
【讨论】:
在 VS 上是/W4
而不是 -Wall
@MikeMB,看here 它是 -Wall
即使在 Visual Studio 上。 Visual Studio 上的所有选项都可以以/
或-
为前缀
是的,有 Wall,但是在代码库上,如果从一开始就没有用它编译,那它是非常没用的,因为你被埋在一堆误报之下。它实际上是在激活所有警告(甚至比 gcc/clang 上的 -Wextra 更具侵略性)
@MikeMB:忽略警告不是一个好习惯。一次解决数百个问题是不可能的,但有时您可以使用 Wall 进行编译,修复一两个软点,然后回到更安静的选项来处理更紧迫的工作。
@MartinBonner,您的话在上帝的耳中:bool
是一种内在的 C++ 类型。 BOOL
是 int
(VS 2015) 的特定于 Windows 的 typedef。查看this page 会发现bool
的大小为1 字节,而BOOL
的大小为4。如果您的假设在未来某处失败,请不要感到惊讶。看this article【参考方案3】:
正如其他人所说:首先,尝试找出错误,而不是隐藏它们。
-
第一个也是最简单的措施是将警告级别设置为
/W4
(您可以尝试Wall
,但由于这会产生大量噪音(例如来自标准头文件),它通常只是有帮助的如果你知道你的代码的某个部分有错误)
使用静态分析器 - 您可以从内置的 Code Analysis
工具开始,然后使用外部工具(对于非平凡的项目,这些工具通常更难以正确设置)。
编写大量测试并确保您正在执行边缘情况 - 这就是 UB 通常潜伏的地方。
如果可能,请尝试在 clang 下编译项目(或其中的一部分)并激活不同的清理程序(特别是 UndefinedBehaviorSanitizer),这将进一步检测您的代码以检查 UB(仅在您有测试时才有帮助锻炼那个UB)
在不同的优化级别和标志组合下测试您的代码(在 VS 中,尤其是 _ITERATOR_DEBUG_LEVEL
有助于发现越界错误)
我想说任何重要的代码库都可能包含未定义的行为。那个特定的程序员有什么特别之处?如果他/她容易出现一种特殊的 UB,那么你可以集中精力解决这个问题。
【讨论】:
以上是关于处理可能包含未定义行为的项目的主要内容,如果未能解决你的问题,请参考以下文章