Hacker News new | ask | show | jobs
by uecker 678 days ago
For example, the following function has obviously no UB:

unsigned int mul(unsigned int x, unsigned int y) { return x * y; }

Or there are many high level function structures as, which also has no UB (with some assumption on the called functions):

void bar() { struct foo *p = foo_alloc(); foo_do1(p); foo_do2(p); foo_delete(p); }

Such code can be easily screened and also this can be done automatically. There is a lack of open-source which can do this, but I have an experimental GCC branch which starts to do this and looks promising.

2 comments

> Or there are many high level function structures as, which also has no UB (with some assumption on the called functions):

    void bar() { struct foo *p = foo_alloc(); foo_do1(p); foo_do2(p); foo_delete(p); }
Are we assuming foo_alloc always succeeds? malloc returns NULL to indicate failure to allocate, which this code wouldn't handle.

> Such code can be easily screened and also this can be done automatically.

That doesn't sound right at all. Robust static analysis of C code is extremely involved. It's an area of ongoing research.

Prior efforts along these lines have not been successful. Even adopting the MISRA C ruleset doesn't guarantee absence of undefined behaviour, for instance.

The first has no UB, but this trivial modification does:

unsigned short mul(unsigned short x, unsigned short y) { return x * y; }

I don't know about you, but I wouldn't think to treat these any differently unless I put on my language lawyer hat.

It is converted to int, so you have a signed multiplication. I don't think you need be a language lawyer to know this, just very basic C.

But I also do not worry about signed overflow anyhow, because compilers can turn them into traps.

I don't think I need to explain why it's unintuitive that multiplying two unsigned numbers sometimes results in a signed multiplication, even though signed types appear nowhere in the code. I couldn't tell you how many times I've seen some DSP application taking uint16s and throwing them into a filter without realizing it could be UB.

Language standards shouldn't rely on compiler options to save developers here. There's a lot of compilers in the world that don't support the same range of options GCC and clang have, like CompCert. Those are often the ones building safety-critical applications these days, where trapping would be inappropriate.

I don't think this is intuitive for somebody knowing the rule, but I agree that it is easy to make a mistake here. But this is not the point: The point is that it is still relatively easy to avoid and screen for this problems - not as easy as looking "unsafe" blocks but also not impossibly hard.

Whether trapping is appropriate or not depends on the context, but it surprising to hear as an argument, because Rust also has a fail hard policy...