如何发现未定义的行为

发布于 2024-09-05 07:23:12 字数 242 浏览 17 评论 0原文

有什么方法可以知道您的程序在 C++(甚至 C)中是否有未定义的行为,而无需记住整个规范?

我问的原因是我注意到很多程序在调试但不在发布中工作的情况 是由于未定义的行为造成的。如果有一个工具至少可以帮助发现 UB,那就太好了,这样我们就知道可能会出现问题。

Is there any way to know if you program has undefined behavior in C++ (or even C), short of memorizing the entire spec?

The reason I ask is that I've noticed a lot of cases of programs working in debug but not release being due to undefined behavior. It would be nice if there were a tool to at least help spot UB, so we know there's the potential for problems.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

梦归所梦 2024-09-12 07:23:12

良好的编码标准。保护你免受你自己的伤害。这里有一些想法:

  1. 代码必须在最高警告级别编译...没有警告。 (换句话说,当设置为最高级别时,您的代码根本不能引发任何警告。)为所有项目打开错误警告标志。

    这确实意味着当您使用其他人的库时需要一些额外的工作,因为他们可能没有这样做。您还会发现一些毫无意义的警告...根据您的团队的决定单独关闭这些警告。

  2. 始终使用RAII

  3. 永远不要使用 C 风格的强制转换!永远不要! - 我认为有一些罕见的情况,你必须打破这个,但你可能永远找不到它们。

  4. 如果您必须reinterpret_cast或强制转换为void,请使用包装器来确保您始终强制转换为同一类型或从同一类型强制转换。换句话说,将指针/对象包装在 boost::any 中,并将指向它的指针转换为您需要的任何内容,并在另一侧执行相同的操作。为什么?因为您始终知道要reinterpret_cast 的类型,并且 boost::any 将强制您在此之后强制转换为正确的类型。这是最安全的。

  5. 始终 在声明时初始化变量(或者在类中的构造函数初始值设定项中)。

还有更多,但这些是一些非常重要的开始。

没有人能记住这个标准。我们中级到高级 C++ 程序员所做的就是使用我们知道安全的构造并保护自己免受人性的影响……并且我们不会使用不安全的构造,除非必须这样做,然后我们会格外小心以确保危险全部隐藏在一个经过严格测试的安全界面中。

要记住的一件重要的事情在所有语言中都是通用的,那就是:

使您的构造易于正确使用且难以错误使用

Good coding standards. Protect you from yourself. Here are some ideas:

  1. The code must compile at the highest warning level... without warnings. (In other words, your code must not set off any warnings at all when set to the highest level.) Turn on the error on warning flag for all projects.

    This does mean some extra work when you use other peoples' libraries since they may not have done this. You will also find there are some warnings which are pointless... turn those off individually as your team decides.

  2. Always use RAII.

  3. Never use C style casts! Never! - I think there's like a couple rare cases when you have to break this but you will probably never find them.

  4. If you must reinterpret_cast or cast to void then use a wrapper to make sure you're always casting to/from the same type. In other words, wrap your pointer/object in a boost::any and cast a pointer to it into whatever you need and on the other side do the same. Why? Because you will always know what type to reinterpret_cast from and the boost::any will enforce that you've cast to the correct type after that. It's the safest you can get.

  5. Always initialize your variables at the point of declaration (or in constructor initializers when in a class).

There are more but those are some very important ones to start with.

Nobody can memorize the standard. What we intermediate to advanced C++ programmers do is use constructs we know are safe and protect ourselves from our human nature... and we don't use constructs that are not safe unless we have to and then we take extra care to make sure the danger is all wrapped up in a nice safe interface that is tested to hell and back.

One important thing to remember which is universal across all languages is to:

make your constructs easy to use correctly and difficult to use incorrectly

維他命╮ 2024-09-12 07:23:12

不可能在所有情况下都检测到未定义的行为。例如,考虑x = x++ + 1;。如果您熟悉该语言,您就会知道它是 UB。现在,*p = (*p)++ + 1; 显然也是 UB,但是 *q = (*p)++ + 1; 呢?如果 q == p 则为 UB,但除此之外它已定义(如果看起来很尴尬)。在给定的程序中,很可能证明 pq 在到达该行时永远不会相等,但通常无法做到这一点。

为了帮助发现 UB,请使用您拥有的所有工具。好的编译器至少会对更明显的情况发出警告,尽管您可能必须使用一些编译器选项才能获得最佳覆盖范围。如果您有更多静态分析工具,请使用它们。

代码审查对于发现此类问题也非常有用。如果您有多个可用的开发人员,请使用它们。

It's not possible to detect undefined behavior in all cases. For example, consider x = x++ + 1;. If you're familiar with the language, you know it's UB. Now, *p = (*p)++ + 1; is obviously also UB, but what about *q = (*p)++ + 1;? That's UB if q == p, but other than that it's defined (if awkward-looking). In a given program, it might well be possible to prove that p and q will never be equal when reaching that line, but that can't be done in general.

To help spot UB, use all of the tools you've got. Good compilers will warn for at least the more obvious cases, although you may have to use some compiler options for best coverage. If you have further static analysis tools, use them.

Code reviews are also very good for spotting such problems. Use them, if you've got more than one developer available.

葬心 2024-09-12 07:23:12

诸如 PC-Lint 之类的静态代码分析工具可以提供很大帮助

Static code analysis tools such as PC-Lint can help a lot here

帅哥哥的热头脑 2024-09-12 07:23:12

我认为您可以使用 coverity 中的一种工具来发现将导致未定义行为的错误。

我想你可以使用 定理证明 (我只知道 Coq)确保您的程序执行您想要的操作。

I think you can use one tool from coverity to spot bugs which are going to lead to undefined behavior.

I guess you could use theorem provers (i only know Coq) to be sure your program does what you want.

带上头具痛哭 2024-09-12 07:23:12

当遇到未定义的行为时,clang尽力发出警告。

clang tries hard to produce warnings when undefined behavior is encountered.

满身野味 2024-09-12 07:23:12

我不知道有任何软件工具可以检测所有形式的 UB。显然,使用编译器的警告以及可能的 lint 或其他静态代码检查器会有很大帮助。

另一件很有帮助的事情就是经验:你对语言进行编程的次数越多,你就越会发现可疑的结构,并能够在过程中尽早发现它们。

I'm not aware of any software tool to detect all forms of UB. Obviously using your compiler's warnings and possibly lint or another static code checker can help a lot.

The other thing that helps a lot is simply experience: The more you program the language, the more you'll see constructs that appear suspect and be able to catch them earlier in the process.

乱世争霸 2024-09-12 07:23:12

不幸的是,没有办法检测所有的UB。为此,您必须解决停止问题。

你能做的最好的事情就是了解尽可能多的规则,当你有疑问时查找它,并与其他程序员核实(通过结对编程、代码审查或只是这样的问题)

编译时出现尽可能多的警告,并且在多个编译器下可以提供帮助。并且通过Valgrind等静态分析工具运行代码可以检测到很多问题。

但最终,没有任何工具可以检测到这一切。

另一个问题是许多程序实际上必须依赖UB。一些 API 需要它,并且假设“它适用于所有正常的编译器”。 OpenGL 在一种或两种情况下会这样做。 Win32 API 甚至无法在符合标准的编译器下进行编译。

因此,即使您拥有神奇的 UB 检测工具,它仍然会因不受您控制的情况而出错。

Unfortunately, there is no way way to detect all UB. You'd have to solve the Halting Problem to do that.

The best you can do is to know as many of the rules as possible, look it up when you're in doubt, and check with other programmers (through pair programming, code reviews or just SO questions)

Compiling with as many warnings as possible, and under multiple compilers can help. And running the code through static analysis tools such as Valgrind can detect many issues.

But ultimately, no tool can detect it all.

An additional problem is that many programs actually have to rely on UB. Some API's require it, and just assume that "it works on all sane compilers". OpenGL does that in one or two cases. The Win32 API won't even compile under a standards compliant compiler.

So even if you had a magic UB-detecting tool, it would still be tripped up by the cases that aren't under your control.

删除会话 2024-09-12 07:23:12

很简单:不要做你不知道自己能做的事情。

  • 当你不确定或有可疑的感觉时,请检查参考资料

Simple: Don't do things that you don't know that you can do.

  • When you are unsure or have a fishy feeling, check the reference
烈酒灼喉 2024-09-12 07:23:12

一个好的编译器,例如英特尔 C++ 编译器,应该能够发现 99% 的未定义行为情况。您需要研究要使用的标志和开关。一如既往,阅读手册。

A good compiler, such as the Intel C++ compiler, should be able to spot 99% of cases of undefined behaviour. You'll need to investigate the flags and switches to use. As ever, read the manual.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文