10 ms·
Better solution, don't use languages that allow undefined behaviour.
by DanWaterworth 13y ago
Better 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.