Comment by pjmlp

3 years ago

GCC's UBSan catches it,

> runtime error: signed integer overflow: 50000000 * 511 cannot be represented in type 'int'

https://godbolt.org/z/oz9vvj5YM

Another heads up of the dangers of UB optimizations, and why using static analysis is a requirement for C derived languages.

If you aren't using all warnings turned on as errors, disabled implicit conversions and at very least have static analysis on the CI/CD pipeline, you're up for a couple of surprises.

From CppCon 2022, "Purging Undefined Behavior & Intel Assumptions in a Legacy C++ Codebase"

https://www.youtube.com/watch?v=vEtGtphI3lc

Yes absolutely, and this is possible today with only open source software. So money is not a barrier.

The sanitizers (UB, address, memory, threads) are supported by both Clang and GCC [1]. Yes that's up to 4 different builds and tests runs but with an automated C/I this is not a big deal.

The Clang static analyzer, with Z3 enabled as a checker, used through CodeChecker [2] is now very good, so much so that I prefer it to a different commercial product showing too many false alarms. Using it on an embedded GCC cross-compiled code base may still require some workarounds, but nothing too bad and this is improving regularly too.

I wouldn't want to do without this. Switching to Rust may not always be possible, and there are big C and C++ code base that will live a long while. Tools like this help and they should be used.

[1] https://github.com/google/sanitizers/

[2] https://codechecker.readthedocs.io/en/latest/

  • Definitly, Java, V8, .NET, Android runtimes still have lots of C++ into them, LLVM and GCC depend on C++ and are comparable to Linux kernel in complexity, GPGPU toolchains, .....

    So reboting into any safe alternative, is going to take decades, hence why the first step is still trying to advocate for best practices, even if it feels like a Quixotic endevour.

Note that UBSan is a dynamic analysis tool.

  • Indeed. But still a good idea to run at least your test-suite with it. And also with address sanitizer and clang's memory sanitizer, etc. Whatever you can find.

  • The static analysis is you compile with it and see if there's any trap instructions emitted by the compiler.

    (The answer is: yes.)

I keep asking this: in my experience sanitizers and other dynamic checkers have always overperformed, while I'm underwhelmed by static analysis. Do people have different experiences?

  • The biggest issue is that too few use them, most surveys place the number around 10% - 20% in such tooling adoption.

Or you know, just turn off UB. I don't know why C still has this, it was useful when we had truly exotic architectures with sign bits &c, but these days it is doing way more harm than good.

  • > Or you know, just turn off UB.

    You cannot “turn off UB”. The behaviour is undefined in the standard, and nothing the compiler can do will make it defined. There is a profound misunderstanding of what undefined behaviour is in a lot of the comments. It is not a compiler setting. The way to make it defined is to change the standard.

    • Right, UB is essential part of C and can't be turned off. But it's entirely possible to turn off integer overflow UB by compiling with -fno-strict-overflow, and you should use it.