4 ms·
Most of the UB in C++ could be well defined within the language if the language just did whatever the machine did (like overflows). The exceptions I can think o
by dataflow 3y ago
Most of the UB in C++ could be well defined within the language if the language just did whatever the machine did (like overflows). The exceptions I can think of are (a) executing invalid code, or (b) access deallocated memory. Java can avoid both of them by taking control of both: you can't execute arbitrary pointers or read/write to arbitrary addresses within the language, and the runtime (I assume) prevents tearing of writes. (This is already guaranteed by the machine on x86, so it doesn't need to do anything there. I can only assume weaker architectures might require atomic instructions for potentially interfering writes, which seems like the cost paid here, but someone can enlighten me.) Furthermore, the GC can ensure that its operations are synchronized with your threads, so you can't interfere with it, and it doesn't pull the rug out from under you. So the end result is that there's theoretically no way to break memory safety.
- jcelerier 3y agofrom the java spec notes: > Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32-bit values. For efficiency's sake, this behavior is implementation-specific; an implementation of the Java Virtual Machine is free to perform writes to long and double values atomically or in two parts. > Implementations of the Java Virtual Machine are encouraged to avoid splitting 64-bit values where possible. Programmers are encouraged to declare shared 64-bit values as volatile or synchronize their programs correctly to avoid possible complications. so in practice Java behaves exactly as C++ for tearing (`volatile` in java having the same meaning than `atomic` in C++) - and if there is a powerful enough optimizer running in the back-end without access of the original semantic information it may well create the kind of UB-led optimizations that people complain about in C++
- dataflow 3y agoIs this only for numbers or also for pointers? Tearing for numbers isn't a memory safety issue, but for pointers it would mean that on a 64-bit machine with tearing, merely reassigning a variable and then calling a method on that object can execute arbitrary machine code.
- vardump 3y agoI’m not aware of any platform that tears aligned pointer stores, but I’ve seen a lot of defensive atomic stores when changing a pointer value. So shrug.
- mort96 3y agoPlatforms where pointers are bigger than the bus width/register size would presumably have tearing in pointer stores... I imagine a JVM implementation for a 16-bit system would want to use 32-bit "far pointers" if the platform supports that.
- raphlinus 3y agoI haven't carefully read the relevant part of the spec, but I imagine that pointers have to be modeled as not subject to tearing, otherwise safety guarantees would completely fall apart. The flip side of this is that adding "fat pointers" safely to Java would be very difficult. Fat pointers are widely used in languages such as Go, Rust, and Swift to represent both slices (pointer + length) and various forms of dynamic dispatch (pointer + vtable). In Rust, this is safe because data races are forbidden, enforced by the type system. I consider Go and Rust to be "safe-ish" in that data races can happen, and can violate safety. Apparently this hasn't led to huge problems in Go. Thus, the roadmap for Carbon[1] targets a comparable level of safety, not trying to prevent data races, but aiming for memory safety in single threaded contexts. [1]: https://www.youtube.com/watch?v=1ZTJ9omXOQ0 https://www.youtube.com/watch?v=1ZTJ9omXOQ0
- layer8 3y agoJava has effectively a non-tearing guarantee for pointers. Regarding performance and alignment, Java pointers are commonly 32-bit even on 64-bit Java, due to compressed pointer representation. (Java objects are always aligned to 8-byte or 16-byte boundaries, so the bottom 3 or 4 bits of a pointer can be shifted out, resulting in 8 or 16 times the normal 32-bit address space. IIRC there are even more variations regarding the Java pointer model.)
- spacechild1 3y ago