7 ms·
Simple solution: remove the undefined behaviour from your codebase.
by octo_t 13y ago
Simple solution: remove the undefined behaviour from your codebase.
- DanWaterworth 13y agoBetter solution, don't use languages that allow undefined behaviour.
- wslh 13y agoDo you mean Haskell? because its compiler is very advanced and does complex optimizations.
- DanWaterworth 13y agoI didn't have a particular language in mind. Though Haskell is certainly a fine choice.
- tel 13y agoIt's semantically well-defined, though. The compiler will never change the value of your result, it will only discover more efficient ways to compute it.
- chongli 13y agoHaskell allows plenty of undefined behaviour! unsafePerformIO, unsafeCoerce, the FFI, even something as simple as unchecked arithmetic can cause it.
- octo_t 13y agowhy? languages like ruby etc dont even have universally defined behaviour - there is no spec etc, just a reference implementation.
- DanWaterworth 13y agoAre you arguing that that is a good thing?
- pjmlp 13y agoRuby has a standard, http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_...
- tinco 13y agoEasy talking, name one?
- mikeash 13y agoIs it hard? I thought that most languages had fully defined behavior, and that C was an exception to this. In case you want specific examples to poke holes in, let's say Java, C#, and Ada.
- ynik 13y agoOnce you add multithreading into the mix, there's plenty of undefined behavior in almost any language. In particular, compiler optimizations can cause surprising effects in programs without sufficient synchronization. In the Java memory model you still get memory-safety in the presence of race conditions, but other than that the program behavior is pretty much undefined. It's better than undefined behavior in C, but not by much.
- mikeash 13y agoThat's an interesting point, I hadn't thought about multithreading. Is it truly undefined in the nasal demons sense, or is it just that the behavior is hard to predict in advance? I assume everyone reading a discussion about undefined behavior knows what nasal demons are, but just in case someone doesn't: in illustrating just what "undefined behavior" means in C, it has been suggested that it would be perfectly legal for a compiler, upon encountering such, to cause demons to fly out of the programmer's nose. The point being that it's not just a matter of producing an unexpected value or something of that nature, but a completely unexpected behavior. As a real-world example, early versions of gcc would, upon encountering a #pragma (whose behavior is undefined) would start a game of nethack.
- tinco 13y agoIt's hard because yes it's true that Java and C# have fully defined behaviour (at least to my knowledge, and when you assume that the garbage collection is optimal) the operations of the VM's themselves are written in C. So you are still dependant on that the programmers of your VM are in control of the undefined behaviour of C. I know that sounds a bit like a cop out, but it lays the finger on the pain point of modern computing, that whatever we do, we are still so heavily reliant on C for everything low level. How would we come close? I'd say name a language whose JIT directly outputs (x86) assembly, and whose runtime is written in a runtime free version that is output by that same JIT. The only language I know of that can do that atm is Rust.
- clarry 13y agoThough this paper focuses on undefined behavior, defined behavior doesn't really make things any better when the programmer makes the wrong assumptions. Look at the first snippet; here the programmer assumed pointer arithmetic behaves like arithmetic in a register where overflow results in wrapping. This might be a reasonable assumption, but this isn't what the spec says. Now you could argue that this should be the defined behavior (and perhaps I would agree), because this is what many programmers will expect. But sooner or later you'll come across a programmer who isn't aware of wrapping and wrongly assumes the value can only grow when a positive integer is added to it. So you could define a language which silently does bignums and all is well, except now you have to deal with memory allocation (this can be a major issue on memory-constrained platforms) during integer arithmetic, and the way bignum computations affect the program's performance & timing (crypto side channel attacks anyone?). So the next programmer again has to know the pitfalls of the Defined behavior and Do The Right Thing, just as he must do now with Undefined Behavior (i.e. rearrange bounds checking and pointer arithmetic so that it'll never point beyond one past the last element of an array; and so that your signed integers never overflow). The second snippet (pointer dereference before NULL check) is perhaps more subtle, and again I might agree that the language would be safer if it didn't allow the removal of the NULL check that would keep this incorrect code from doing further harm. However, no matter what your proposed defined behavior for NULL/invalid pointer dereferencing is (what would it be? I have no idea), there would likely be cases where the programmer makes the wrong assumption and his program relying on that Defined behavior is still incorrect and potentially insecure. Simply defining undefined behavior just doesn't fix incorrect code. You still have to remove the broken (undefined or not) code from the codebase... EDIT: If you meant to suggest languages whose compiler will abort if it finds code that might result in undefined behavior, well, that's much harder. UB in C is predominantly a run-time issue, so you'd be making a really smart static analyzer to detect at compile time whether your code can actually hit UB. Did someone solve the halting problem? Alternatively you can make a language where integers never overflow. Then we get to what I said about bignums and surprise-allocation and such.. Haskell just isn't for everything.
- Dylan16807 13y agoYou can define a null pointer access as what it actually does on the typical architecture, touching the memory at address 0. Obviously this won't magically fix unintentional NULL use, but it will let the kernel-mode dereference-before-check work fine.
- abecedarius 13y agoIt's not simple to find the undefined behavior in C. (As evidenced by the OP being about a tool to help. I've read that clang may be better than gcc at this.) For the sort of code that was best written in C, a few decades ago, it was often reasonable engineering to depend on technically undefined behavior. Then over the decades the compilers made increasingly-subtle transformations without getting much better at telling you where they might have tripped you up (again, maybe except for clang which I haven't tried yet).
- anon1385 13y agoEasier said than done. There are better tools for finding undefined behaviour these days but they are pretty recent and far from perfect. For a taste of how common undefined behaviour is, even in important code bases, (and why everybody should be using tools to test for it) see this post: http://blog.regehr.org/archives/1054 http://blog.regehr.org/archives/1054 "Integer Undefined Behaviors in Open Source Crypto Libraries" Also the follow up about how difficult C sometimes makes it to avoid undefined behaviour without a performance penalty: http://blog.regehr.org/archives/1063 http://blog.regehr.org/archives/1063 "Safe, Efficient, and Portable Rotate in C/C++"
- joosters 13y agogcc 4.9 has a new UndefinedBehaviorSanitizer, -fsanitize=undefined - http://gcc.gnu.org/gcc-4.9/changes.html http://gcc.gnu.org/gcc-4.9/changes.html Perhaps this will help find these coding mistakes? (unfortunately, it seems to be a runtime checker and not a compile-time warning)
- DanWaterworth 13y agoAs others have pointed out, statically determining whether a program will invoke undefined behaviour is undecidable.
- joosters 13y agoAh, but it doesn't have to be exact to be useful. Spotting common cases and minimising false positives would be great, even if there was no guarantee of catching everything.
- Groxx 13y agoThat's like saying the halting problem is undecidable. Just because we can't make a general-case solution doesn't mean there isn't progress to be made.
- emillon 13y agoUndefined behaviour is a dynamic property, not language constructs. It's akin to saying "remove run-time errors from your programs".
- Dylan16807 13y agoOnly a specific class of error. And you can do that. It's hard, but you can do it.
- deleted 13y ago[deleted]