Live data from Hacker News

Breaking java.lang.String

wouter.coekaerts.be

111–120 of 206 posts

Re: Breaking java.lang.String

#111
post #75

Earlier quoted context omitted.

Author of the blog here. Yes, this is a bug. While the javadoc doesn't state it explicitly, immutable classes in the core library are expected to be thread safe. Java tries to be and mostly succeeds at being a safe language, where (by default) the guarantees of its internals cannot be broken no matter what user code does. The JVM preserves its own integrity. There are some other deliberate holes in that safety, such…

Dunno, this seems like you're violating the java memory model and then then fully expected weird shit happens. If you're mutating a shared state between threads without proper synchronization, and there is no way for String to do this on its own, the CPU is permitted to do stuff like out-of-order execution as there is no happens-before relationship between the write and the read. The JVM is further permitted to optim…

I didn't think it was a bug either till I got to the "Spooky action at a distance" section. The fact that the following code:

"hello world".startsWith("hello")

can return false in any circumstance, is a bug in the language. The fact that some other code in an entirely unrelated part of the codebase can intern a broken string and thus break string-comparisons for the entire codebase, is mind boggling.

Fortunately, I don't think the fix needs to be too expensive. After a defensive copy of the byte-array is made, just before returning the newly constructed string object, verify once again that the chosen coder matches the string contents. If it doesn't, that would imply a race condition, and the broken string instance should not be returned

Re: Breaking java.lang.String

#113
post #75

Earlier quoted context omitted.

Author of the blog here. Yes, this is a bug. While the javadoc doesn't state it explicitly, immutable classes in the core library are expected to be thread safe. Java tries to be and mostly succeeds at being a safe language, where (by default) the guarantees of its internals cannot be broken no matter what user code does. The JVM preserves its own integrity. There are some other deliberate holes in that safety, such…

In my opinion this is not a bug and there is no general fix for that without significant overhaul of the whole runtime and standard library. In my opinion the author might need to read the vm and memory model spec and understand that such things are expected in Java. There are real bugs in standard library singletons (e.g. concurrent Filesystem calls might fail during singleton initialization, while plugins are loade…

A defensive copy is the cheap way to fix this.

The bug is a potential security vulnerability since it can affect the value of interned strings, which can break other libraries.

Re: Breaking java.lang.String

#114

> Why is "foo!".equals("foo⁉") false? I don't really understand this question. They...look different? One is an exclamation mark, and the other is an exclamation mark/question mark combo?

This is not a question.

The paragraph after that get into the implementation details on how have know they are different without comparing the bytes.

Re: Breaking java.lang.String

#115
post #81
post #75

Earlier quoted context omitted.

Author of the blog here. Yes, this is a bug. While the javadoc doesn't state it explicitly, immutable classes in the core library are expected to be thread safe. Java tries to be and mostly succeeds at being a safe language, where (by default) the guarantees of its internals cannot be broken no matter what user code does. The JVM preserves its own integrity. There are some other deliberate holes in that safety, such…

How would you fix this? Possibly by copying the input array to a local array as the first step? But then you might copy a lot of data, which is in 99% of the cases totally unnecessary. Have a separate threadsafe and a non-threadsafe constructor for char[]? EDIT: another idea is to do a hash of the input array, and compare between start and end. But that also requires an O(n) walk through the input...

Copy the array, then use alias analysis to remove the copy most of the time, by having two versions of the String constructor, with a version chosen based on aliasing.

Re: Breaking java.lang.String

#116

Calling 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…

This bug can change the meaning of code in third party libraries by altering the set of interned strings.

If any input to a program can be converted into this race, then it becomes a security vulnerability. It would already be a security vulnerability in the old Java sandbox model.

Re: Breaking java.lang.String

#117
post #91

Earlier quoted context omitted.

Yes, but at some point one has come out of the theory domain and face the real world. So in practical terms it’s closer to a bug and even the “official” guys from Java accepted it as a bug.

Could you provide a link to the documentation to proof it's a bug? The author could call it 'probably bug' or 'misleading String constructor documentation' but instead they state it's a bug without any proofs.

Here: https://bugs.java.com/bugdatabase/view_bug?bug_id=JDK-831190...

It was accepted as a bug. I'm not saying I would condemn anyone to the death penalty based on that but being accepted as a bug there has to have a significant weight attached to it.

Re: Breaking java.lang.String

#118

Earlier quoted context omitted.

In my opinion this is not a bug and there is no general fix for that without significant overhaul of the whole runtime and standard library. In my opinion the author might need to read the vm and memory model spec and understand that such things are expected in Java. There are real bugs in standard library singletons (e.g. concurrent Filesystem calls might fail during singleton initialization, while plugins are loade…

A defensive copy is the cheap way to fix this. The bug is a potential security vulnerability since it can affect the value of interned strings, which can break other libraries.

That still has to be done ad-hoc and might kill performance for many usecases.

This is not a bug, but a specified behavior.

Re: Breaking java.lang.String

#119

Earlier quoted context omitted.

In my opinion this is not a bug and there is no general fix for that without significant overhaul of the whole runtime and standard library. In my opinion the author might need to read the vm and memory model spec and understand that such things are expected in Java. There are real bugs in standard library singletons (e.g. concurrent Filesystem calls might fail during singleton initialization, while plugins are loade…

A defensive copy is the cheap way to fix this. The bug is a potential security vulnerability since it can affect the value of interned strings, which can break other libraries.

Even the example in article alone. Imagine someone intern a broken "script" string, and people trying to sanitize HTML script tags no longer find it.

Re: Breaking java.lang.String

#120
post #20

Is 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.

That's true, but in the case of Strings in particular they are generally considered to be thread-safe by virtue of being immutable (and the Javadocs themselves say this in many places). Concurrently modifying the input character array may seem like willful abuse in this case, but I suppose there might be some carelessly written code out there which does it and the post shows how it would create some weird and very ha…

Probably guard intern() instead would be enough? It would be enough to stop the broken string from pollute the whole process permanently.
Post reply on HN