13

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.

Community
  • 1
  • 1
BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283

9 Answers9

17

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

Community
  • 1
  • 1
Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • +3- I'd say more than sound...survival advice ? but still what does happen if 6you have an identified behavior ? – LB40 Jun 10 '10 at 18:15
  • @LB - I assume you meant that to be "unidentified behavior" to go back to the main question? Look for violations of these coding standards. If you have UB it's almost certainly somewhere that you didn't do these things. – Edward Strange Jun 10 '10 at 18:28
5

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.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
3

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

SmacL
  • 22,555
  • 12
  • 95
  • 149
  • +1: for really specific needs, you can also use Coccinelle. (love this tool). You can patch but also detect patterns – LB40 Jun 10 '10 at 18:13
  • @LB thanks, hadn't heard of Coccinelle, must look it up. Always keeping an eye out for new tools – SmacL Jun 11 '10 at 06:04
2

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.

LB40
  • 12,041
  • 17
  • 72
  • 107
  • +1, hadn't seen the coverity product before. Any idea how it compares with PC-Lint? – SmacL Jun 10 '10 at 16:03
  • coverity is really well-known in the academia world... They release each year a report of bugs found in free softwares.. I don't have much experience with PC-Lint or coverity (it seems that coverity claims to be better, but PC-Lint does the same thing -on their front-page). The only thing I know is that huge corporations require pieces of software to be coverity certified – LB40 Jun 10 '10 at 18:12
2

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

Dummy00001
  • 16,630
  • 5
  • 41
  • 63
1

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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

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.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • I realize that, but you would also have to solve the halting problem to detect all buffer overflows - that hasn't stopped people from developing programs that do a good job of it. Interesting bit about Win32 API requiring UB though, didn't know that. – BlueRaja - Danny Pflughoeft Jun 10 '10 at 21:50
  • 1
    An implementation wouldn't have to solve the halting problem to find all Undefined Behavior; it would merely have to define what happens in every case which the C standard leaves undefined. A compiler could produce an output file with a virtual machine implementation and a memory image for it, and document the behavior of the virtual machine in all cases; code produced by such a compiler wouldn't have *any* undefined behavior. – supercat Feb 10 '14 at 17:16
-1

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
piotr
  • 5,657
  • 1
  • 35
  • 60
  • 1
    This only works if you already know you don't know what you can do. Many people are [taught the wrong things](http://stackoverflow.com/questions/2979209/using-fflushstdin) or don't know the literally [thousands](https://connect.microsoft.com/VisualStudio/feedback/details/547423) [of](https://connect.microsoft.com/VisualStudio/feedback/details/519445) [edge](http://stackoverflow.com/questions/1831316) [cases](http://stackoverflow.com/questions/367633/367662#367662) - there is simply no way to *check the reference* for every non-trivial piece of code you write... – BlueRaja - Danny Pflughoeft Jun 10 '10 at 16:31
  • @BlueRaja: If people are taught the wrong things, they'll write bad programs no matter what. If people are willing to hit the edge without looking, then they will run afoul of edge cases, no matter what. In either of those cases, it doesn't really matter if you're talking about undefined behavior or behavior that's defined but not necessarily what you expected. It's not that difficult to learn to program in C or C++ safely, and if you're smart you check when you leave your comfort zone in any language. – David Thornley Jun 10 '10 at 17:32
-3

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.

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
  • 1
    99%? False sense of security. A good compiler can catch more issues than a bad one, but it's still only a fraction of all the possible cases. – jalf Jun 10 '10 at 16:49