6 ms·
Undefined Behaviour Canaries
- TheLoneWolfling 11y agoIs there a C-like language that's sane by default? One where, for example, uninitialized values are defined as though they are set to some arbitrary value?
- pcwalton 11y agoDo you mean that syntactically uninitialized values are set to some well-defined value (0, for example), or one in which uninitialized values have an undefined value but don't cause undefined behavior on use?
- TheLoneWolfling 11y agoNot where they are set to a constant. Just that they behave consistently. So, for example, x - x == 0 for int x, even if x is uninitialized. (Basically, it behaves as though x was set to some value, although that value may vary from object to object and from run to run.)
- masklinn 11y ago> Just that they behave consistently. Erroring out because the variable is not initialised is consistent yes?
- TheLoneWolfling 11y agoYes, but erroring out on something like that is not good for other reasons. Among other things, that moves it from a local problem to a global problem. It's the same problem with undefined behavior in general. It's an example of a local problem causing global problems. You don't want your rocket to crash just because something threw an unchecked exception.
- masklinn 11y ago> You don't want your rocket to crash just because something threw an unchecked exception. Good news: the error is a compile-time error, not a runtime error.
- TheLoneWolfling 11y agoYou hope. And then you run into something like this [1] - which has been open for >10 years, and all of a sudden you're invoking UB without realizing it. [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=18501 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=18501
- pcwalton 11y agoI'm not aware of a language designed for programmers that works like this, but LLVM IR's undef works like that. http://llvm.org/docs/LangRef.html#undefined-values http://llvm.org/docs/LangRef.html#undefined-values
- TheLoneWolfling 11y agoNo it doesn't. For example, in LLVM "x - x" for int x isn't always zero if x is undef. (Skipping over syntax here) Quoting from the linked document: > This can be surprising to people (and also matches C semantics) where they assume that “X^X” is always zero, even if X is undefined. > the short answer is that an ‘undef‘ “variable” can arbitrarily change its value over its “live range”.
- pcwalton 11y agoOh, you actually want a live range to be allocated for the value. No, I'm not aware of any programming language that works like this (nor do I think the benefits would be worth it since you'd be increasing register pressure).
- TheLoneWolfling 11y agoI'm not so sure. The number of debugging hours that have been spent because of UB causing globally logically inconstant behavior... And it's better in terms of register pressure than the standard alternative - namely implicitly initializing everything.
- chongli 11y agoSo you want a language with a computer algebra system (CAS) that reduces expressions such as "x - x" at compile time. This has been doable in Lisp for a long time using macros. It'd be a bit trickier to do in a C-like language due to the syntax but still reasonable.
- TheLoneWolfling 11y ago
- InclinedPlane 11y agoRust?
- TheLoneWolfling 11y agoRust, like most memory-safe languages, requires initialization, implicit or explicit. This is not quite the same thing.
- xamuel 11y agoWhy on earth would you want a language where { int i; if (x) return; i=2; ... } generates more opcodes and takes more CPU time to run than { if (x) return; int i; i=2; ... }? That doesn't seem very sane to me.
- nitrogen 11y agoThe variable i only needs to be initialized if it is accessed before being assigned, or if one wants the local stack to be cleared at every function call to avoid data leaks from previous/to later function calls. The second case explains why someone might want int i; do_something(); i = 2; to behave differently from do_something(); int i = 2;
- xamuel 11y ago'Telling whether i will be accessed before being assigned' is equivalent to the halting problem. In your example, the only way the two options could differ would be if do_something() was dereferencing an invalid pointer that pointed at i. So what you really want is some kind of pointer guard, not automatic variable initialization.
- nitrogen 11y ago'Telling whether i will be accessed before being assigned' is equivalent to the halting problem. Not in C it isn't, thanks to variable scope.
- TheLoneWolfling 11y ago> 'Telling whether i will be accessed before being assigned' is equivalent to the halting problem. This is true. However, figuring out the most efficient program that's equivalent to a given program also suffers from the halting problem, and that's literally the definition of the goal of an optimizer. So no: in general you cannot prove if an arbitrary variable will be accessed. However, you can, and will, take a conservative approach and narrow it down as much as possible. In other words, if you can prove that it will be accessed before being assigned, great. If you can prove that it won't be accessed before being assigned, great. If you can't prove either... Meh, you have to include a redundant store. It's exactly the same way that optimizers work to, for example, remove redundant stores to a variable. Because it is. Except that, if you read carefully, what I proposed wasn't quite the same thing. I'm proposing a language where a read from an uninitialized variable must be consistent with the uninitialized variable having been set to an arbitrary value (in range) before the first read from it. So compiling the static code {int x; return x;} into {return 0;} is perfectly allowed, as is compiling it into {return 42;}.
- masklinn 11y ago* Go and D initialise all variables * Ada can do so using the Normalize_Scalars (though by default it'll just read whatever garbage is at that location) however the initialisation value is implementation defined (it's recommended that the value be invalid, so that an access to an uninitialised value faults) * Rust requires that all control paths initialise variables Both Clang and GCC can warn about potentially uninitialised variables (using -Wuninitialized in Clang and -Wmaybe-uninitialized in GCC, both being in -Wall)
- TheLoneWolfling 11y agoInitialization is not the same thing, though, for everything but Ada. I'm not looking for a c-like language where variables must be defined / are implicitly initialized to a constant. Those have problems, among other things the cost of double-initialization. I'm looking for a c-like language where the compiler is free to assume that an uninitialized variable is anything it wants - but it must be consistent about it. So, for example, "return x - x", where x is an integer, will always return zero.
- masklinn 11y ago> Those have problems, among other things the cost of double-initialization. Compilers optimise away significantly more complex things than initialising a variable twice. > I'm looking for a c-like language where the compiler is free to assume that an uninitialized variable is anything it wants - but it must be consistent about it. So, for example, "return x - x", where x is an integer, will always return zero. So you're looking for C? Because whatever garbage's in there will be the same garbage in both references to x. I have issues with your qualification of that as "sane" though.
- TheLoneWolfling 11y agoDid you read the article? In C, the compiler is perfectly allowed to compile "return x - x" with x uninitialized into "return 1". Accessing an uninitialized variable in C is undefined behavior. The compiler can do anything. Nasal daemons. > Compilers optimise away significantly more complex things than initialising a variable twice. Right, but there are cases where being required to initialize a variable to, say, 0, is not equivalent than being required to initialize a variable to <some arbitrary value>. For instance, "if (x == 0) y = someExpensiveFunction();" with x being uninitialized. With the "must be initialized to a specific constant" this sort of thing cannot be optimized, whereas with "must be consistent" this can be compiled down to nothing.