Live data from Hacker News

Undefined Behavior in 2017

blog.regehr.org

31–40 of 120 posts

Re: Undefined Behavior in 2017

#31

Why don't compilers have an option to reject UB with an compiler error? Surely the compiler must know when it comes across a piece of source code whose semantic is undefined.

Because compiler don't generally look for UB then gleefully cackle as they fuck up your code.

Rather they are written under the assumption that there are no UB in the program, and the chips fall where they may as these assumptions are used and propagated.

Re: Undefined Behavior in 2017

#32
post #20

I wonder why he mentions this TIS interpreter but not the development of complete semantics for C and specifically the k framework ( https://github.com/kframework/c-semantics ). Afaik, kcc is also really good at finding undefined behavior. Regehr even wrote about it in the past ( https://blog.regehr.org/archives/523 ).

AFAIR from the last presentation on the K framework I attended (a year ago), the publicly available version of their C interpreter is incomplete: It only runs programs that don't need the standard library. That's pretty great for many things! But it's not a turnkey solution for analyzing real applications. For that they had a proprietary commercial version. (Again, this is from memory, and it may have changed.)

Another reason to mention TIS-interpreter specially is that Pascal Cuoq (the co-author of this blog post) is one of its developers, and his livelihood depends on it being used.

Re: Undefined Behavior in 2017

#33
post #2

How many of these 200+ undefined behaviours exist in more modern low-level languages, such as Rust and D?

In Rust it's pretty limited. Here is the full list, from the Rustonomicron: Dereferencing null or dangling pointers Reading uninitialized memory Breaking the pointer aliasing rules Producing invalid primitive values: dangling/null references a bool that isn't 0 or 1 an undefined enum discriminant a char outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] a non-utf8 str Unwinding into another language Causing a da…

> Note that all of these are inside of unsafe blocks. Besides unsafe blocks, Rust has no undefined behavior, and the compiler will prevent you from doing any of these things.

It's true that unsafe is needed to get these problems, but they can also occur outside of unsafe blocks. See an example here: https://gankro.github.io/blah/only-in-rust/#unbound-lifetime...

Your own code need not use "unsafe" at all, but the program may still crash in your code if you called some function that internally does unsafe things to mess up your memory.

EDIT: I should say that the linked code does not crash, it only reads uninitialized memory. It seems to me like the same hole could be used to make things crash, but I don't have a ready-made example.

Re: Undefined Behavior in 2017

#34
post #16
post #12

I wish there was a GCC switch that made the optimizer go "This is clearly undefined behaviour. I'll stop this compile right here", as opposed to "This is clearly undefined behaviour. Sweet jackpot, it means I can do whatever the heck I want. Drop those NULL checks below, I've got the golden UDB ticket now"

The optimizer doesn't work that way. It assumes the code does not do UB and then removes branches that can never be taken if the code executes no UB. That's different from "This is UB, and now I do ...".

I think we deserve a compiler warning whenever a source line of code (not a line generated by the preprocessor) gets removed due to UB exploitation. All such cases are worth the programmer's attention, because they are either useless lines or bugs.

Re: Undefined Behavior in 2017

#35
post #25
post #2

How many of these 200+ undefined behaviours exist in more modern low-level languages, such as Rust and D?

LuaJIT is another modern low-level language. It has some remarkable undefined behavior like the evaluation order for function arguments. Scares me a bit. https://github.com/LuaJIT/LuaJIT/issues/238

The same is true in C/C++: Function argument evaluation order is unspecified. BUT: that doesn't mean this is undefined behavior, it is just unspecified.

unspecified != undefined behavior

See this Stack overflow answer for an explanation: https://stackoverflow.com/questions/2397984/undefined-unspec...

Re: Undefined Behavior in 2017

#36
post #17
post #13

Earlier quoted context omitted.

Because a lot of UB cannot be efficiently determined at compile time. Hence, UBSan.

It is very easy to be efficiently determined at compile time, other systems programming languages do it, by not having UB on their language standard to start with. If people prefer "performance trumps correctness" and "winning compiler benchmarks is what counts" then they should happily keep getting exploited.

"Very easy" - well, if you think garbage collection is easy...

And yes, if you want to allow manual allocation of objects and setting pointers to arbitrary objects, then your two choices are: 1) garbage collection 2) undefined behavior (use-after-free, double-free, dangling pointers, etc.)

Re: Undefined Behavior in 2017

#37
post #16

Earlier quoted context omitted.

The optimizer doesn't work that way. It assumes the code does not do UB and then removes branches that can never be taken if the code executes no UB. That's different from "This is UB, and now I do ...".

I think we deserve a compiler warning whenever a source line of code (not a line generated by the preprocessor) gets removed due to UB exploitation. All such cases are worth the programmer's attention, because they are either useless lines or bugs.

It's more complicated than this, unfortunately. Imagine an int variable x and two expressions f(x) and g(x) of x. Now imagine an if statement with condition f(x) x is always true. So it's not necessary for the line to be useless or wrong for undefined behavior rules to trigger compiler optimizations.

Re: Undefined Behavior in 2017

#38
post #36
post #17

Earlier quoted context omitted.

It is very easy to be efficiently determined at compile time, other systems programming languages do it, by not having UB on their language standard to start with. If people prefer "performance trumps correctness" and "winning compiler benchmarks is what counts" then they should happily keep getting exploited.

"Very easy" - well, if you think garbage collection is easy... And yes, if you want to allow manual allocation of objects and setting pointers to arbitrary objects, then your two choices are: 1) garbage collection 2) undefined behavior (use-after-free, double-free, dangling pointers, etc.)

> garbage collection is easy...

Garbage collection isn't the only way of writing mostly safe systems programs.

ESPOL, NEWP are 10 year older than C.

PL/8 was the systems programming language used by IBM for their first RISC mainframe, followed by PL/S.

Mesa used at Xerox PARC.

Modula-2 used at ETHZ and many 16 bit systems.

Object Pascal used to write the first versions of Mac OS and Lisa.

Ada and SPARK used by high integrity systems where human lives can be at risk.

All of them with not even a quarter of C's UB collection.

Re: Undefined Behavior in 2017

#39
post #2

How many of these 200+ undefined behaviours exist in more modern low-level languages, such as Rust and D?

In Rust it's pretty limited. Here is the full list, from the Rustonomicron: Dereferencing null or dangling pointers Reading uninitialized memory Breaking the pointer aliasing rules Producing invalid primitive values: dangling/null references a bool that isn't 0 or 1 an undefined enum discriminant a char outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] a non-utf8 str Unwinding into another language Causing a da…

>, Rust has no undefined behavior,

Correct me if I'm wrong but I don't think such a strong universal statement can be true (even outside unsafe blocks) because LLVM has corner cases of "undefined behavior". (And since Rust is relies on LLVM, ...)

Maybe it's more accurate to say that Rust minimizes undefined behavior as a design goal, or it doesn't have intentional undefined behavior.

Re: Undefined Behavior in 2017

#40

Earlier quoted context omitted.

In Rust it's pretty limited. Here is the full list, from the Rustonomicron: Dereferencing null or dangling pointers Reading uninitialized memory Breaking the pointer aliasing rules Producing invalid primitive values: dangling/null references a bool that isn't 0 or 1 an undefined enum discriminant a char outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] a non-utf8 str Unwinding into another language Causing a da…

> Note that all of these are inside of unsafe blocks. Besides unsafe blocks, Rust has no undefined behavior, and the compiler will prevent you from doing any of these things. It's true that unsafe is needed to get these problems, but they can also occur outside of unsafe blocks. See an example here: https://gankro.github.io/blah/only-in-rust/#unbound-lifetime... Your own code need not use "unsafe" at all, but the pro…

The important quote from the article you linked is: "But what happens when we throw some unsafe code at the issue?", so the claim that safe Rust doesn't have UB (that isn't considered a bug in the compiler) still stands. If you mix in unsafe code, bad things may happen, regardless of whether you wrote the unsafe yourself or rely on a library.
Post reply on HN