Out of interest, how should this be handled? Is this a bug in Java which should be fixed (looks like that to me)? My understanding was Java generally doesn't do "you did an undefined behaviour, so it's your fault", except for specifically marked very low-level interfaces.
If I would design JVM from the scratch, I'd introduce frozen arrays. There are so many array copies inside JDK code, it hurts. Whether it's possible to retrofit JVM today, I don't know.
Breaking java.lang.String
61–70 of 206 posts
Re: Breaking java.lang.String
#62Earlier quoted context omitted.
This is a heavily optimized system library - you don’t use mutexes here. Rust wouldn’t help here, if mutexes would be fine, they would have been used. Especially that this is the result of C++ and Java code simultaneously. Hell, it’s probably one area where rust’s benefits are a “hard sell” — you would have to constantly be in unsafe rust manipulating pointers manually as the compiler can’t reason statically about wh…
No idea why Thaxll and the other comments are mentioning mutexes. The equivalent (*) API to this Java API in Rust does exist; it's `String::from_utf8(Vec ) -> String`. And the bug in TFA does not exist there. Since the signature consumes the `Vec ` it's impossible for the caller or any other code to still have access to it to be able to modify it concurrently. Also consider the similar API `str::from_utf8(&[u8]) -> &…
Thaxll mentioned mutexes in a reply to the statement
Java has no way to express the concept of "something that nothing else can modify while I'm looking at it"
Even ignoring the performance aspect that is not the perfect answer, though. AFAIK, the JVM doesn’t have a notion of “you can only modify foo if you hold mutex bar”. That remains something the programmer must enforce.
On the other hand, tooling exists to help them, for example https://www.javadoc.io/doc/com.google.code.findbugs/annotati...
Re: Breaking java.lang.String
#63Earlier quoted context omitted.
The scenario I was imagining and commenting on was about “implementing a JVM with Java’s semantics in Rust”. Of course if we limit the language itself to safe Rust, we get data race freedom, but at a quite significant price for a high level language (it constraints possibly correct programs down a lot ). But Rust would not help with relation to the primitives here at all (implemented in C++/Java).
"Rust wouldn't help" "This bug can't be implemented in rust" "I meant that Rust doesn't fix the bug in Java. Even if you write rust code, you can also write buggy java code too so rust didn't fix the java code" You're the only one here who thought "rust" meant "java semantics implemented in rust" in this context.
If we put Java on top of Rust, then no, Rust no longer can help about this. That was my whole point.
Re: Breaking java.lang.String
#64Earlier quoted context omitted.
As the article points out, the only thing the Javadoc guarantees is the subsequent modifications of the character array have no effect. It says nothing about concurrent modifications. The type whose thread safety is in question here is not actually String, but char[]. I'm not going to say it is always wrong to share char[] between threads (as a primitive array of something other than double and long, the Java Spec do…
While you are technically right in all your points, I think you exaggerate the problems regarding Java’s type system. Arrays are indeed a pain point from different times (the mistake of their covariance even “infected” C#), but generics are not problematic at all. In fact, code that compiles without warning is guaranteed to never get a ClassCastException. Every language’s type system gives you escape hatches, so that…
The correct way to do this is use the MaybeUninit type. Then you're responsible for correctly initializing a T before you call MaybeUninit::assume_init() to get a T.
Re: Breaking java.lang.String
#65Earlier quoted context omitted.
"Rust wouldn't help" "This bug can't be implemented in rust" "I meant that Rust doesn't fix the bug in Java. Even if you write rust code, you can also write buggy java code too so rust didn't fix the java code" You're the only one here who thought "rust" meant "java semantics implemented in rust" in this context.
Because in case of the problem at hand, this is a complex interplay between Java's standard library's Java code and the underlying JVM. There is not much to discuss regarding "rust would make the code safe", because so does JS as it is single threaded.. That's hardly interesting. If we put Java on top of Rust, then no, Rust no longer can help about this. That was my whole point.
Rust and javascript having differences which prevent this class of bugs might not be very interesting, but it's more interesting than your point.
Unless I'm misunderstanding, your point is that a bug in Java cannot be avoided by switching languages to Java.
Re: Breaking java.lang.String
#66Is this actually a bug? The default assumption in Java is that types are not thread-safe unless otherwise specified. Attempting to use types in a way that exceeds their documented thread safety has always been allowed to leave your program in an inconsistent state.
> Attempting to use types in a way that exceeds their documented thread safety has always been allowed to leave your program in an inconsistent state. Wasn't there an attempt for Java to define the range of outcomes even of programs with data races?
More specifically Java says something like, if you race a value of some sort, even a complex value like a hash table, it doesn't get fatally damaged, but its new state is some state it had, or might have during other executions.
Re: Breaking java.lang.String
#67Is this actually a bug? The default assumption in Java is that types are not thread-safe unless otherwise specified. Attempting to use types in a way that exceeds their documented thread safety has always been allowed to leave your program in an inconsistent state.
I remember a bug in Visual/Digitalk Smalltalk: conversion from integer to string (method printString) was not thread safe, because it used global buffer for better performance. Very rarely - when we used a progress indicator in another thread (called Process in Visual Smalltalk) - this global buffer was overriden by another integer to string conversion... It took a year to find out the reason why our code sometimes g…
Re: Breaking java.lang.String
#68Earlier quoted context omitted.
Because in case of the problem at hand, this is a complex interplay between Java's standard library's Java code and the underlying JVM. There is not much to discuss regarding "rust would make the code safe", because so does JS as it is single threaded.. That's hardly interesting. If we put Java on top of Rust, then no, Rust no longer can help about this. That was my whole point.
> That's hardly interesting Rust and javascript having differences which prevent this class of bugs might not be very interesting, but it's more interesting than your point. Unless I'm misunderstanding, your point is that a bug in Java cannot be avoided by switching languages to Java.
Re: Breaking java.lang.String
#69Earlier quoted context omitted.
While you are technically right in all your points, I think you exaggerate the problems regarding Java’s type system. Arrays are indeed a pain point from different times (the mistake of their covariance even “infected” C#), but generics are not problematic at all. In fact, code that compiles without warning is guaranteed to never get a ClassCastException. Every language’s type system gives you escape hatches, so that…
> how one might implement an optimization library in Rust where you have uninitiated elements The correct way to do this is use the MaybeUninit type. Then you're responsible for correctly initializing a T before you call MaybeUninit ::assume_init() to get a T.
(nonetheless, thanks for mentioning the MaybeUninit, that was what I was thinking of, but didn't remember the name -- I haven't programmed in Rust for a long time)
Re: Breaking java.lang.String
#70Calling this a "bug in java.lang.String" is silly. The same "bug" exists for all functions that take mutable objects. If you take a map and lookup two different keys, yep, that's a "bug". The bug is the other piece of code that introduces the data race in the first place. You can argue the case for languages like Rust with it's borrow system, or others that use linear types or something along those lines, to eliminat…