Live data from Hacker News

Breaking java.lang.String

wouter.coekaerts.be

131–140 of 206 posts

Re: Breaking java.lang.String

#131
post #124

Earlier quoted context omitted.

In my opinion the abstraction is leaky but everything works according to the spec. I might tell you about another "bug" and "invariant violation" which is possible but is not a bug. Try to use Sets or Maps with keys having broken hashcode.

I can't agree with this analogy. This is not a defective user implementation of hashcode; it is a defective platform implementation of equals (and starts with, etc.).

This is a broken user code written without any JMM understanding.

Re: Breaking java.lang.String

#132

Earlier quoted context omitted.

I don't think it does. In C++ taking a const argument just means that you can't change it. But since the caller can pass non-const as const there is nothing stopping them from mutating it.

You can also use const_cast to remove the const-ness. You could then mutate the value. I believe that's undefined behavior territory (the mutation, at least in most cases), but I'm sure someone is doing it in the wild.

I haven't done much C++ in a few years but IIRC you can remove const as long as the "original" value isn't const. So `const_cast((*const Foo)foo)` is fine if foo is not const.

Re: Breaking java.lang.String

#133
post #124

Earlier quoted context omitted.

In my opinion the abstraction is leaky but everything works according to the spec. I might tell you about another "bug" and "invariant violation" which is possible but is not a bug. Try to use Sets or Maps with keys having broken hashcode.

I can't agree with this analogy. This is not a defective user implementation of hashcode; it is a defective platform implementation of equals (and starts with, etc.).

A proper implementation of hashcode can return nonsense if you mutate the object during hashing.

Re: Breaking java.lang.String

#134
post #129

Earlier quoted context omitted.

A defensive copy probably doesn't help here. The JVM is permitted to optimize it away, since it has no externally observable effects and doesn't have a constructor.

Wait, really? It's very externally observable in the presence of multithreading. Surely there must be a way to say "no, really, please make a copy".

afaik the person you replied to is wrong, using System.arrayCopy would definitely make a copy and not be optimized away.

Maybe poster meant only copying the reference with `char[] copy = original` which indeed does nothing, but that's not a defensive copy.

Re: Breaking java.lang.String

#135
I just added solutions to the empty String challenge in the blog post. This includes a very interesting find from Xavier Cooney, that causes the same problem without involving any concurrency. It instead makes StringBuilder misbehave by throwing an exception at an unexpected place: https://gist.github.com/XavierCooney/e9f6235f05479ac6bf962ca...

Re: Breaking java.lang.String

#136

Earlier quoted context omitted.

It's a TOCTOU bug [1], a well known category of bugs. [1] https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use

Also one more argument for “parse don’t validate”. The code validates a mutable input, and assumes that validation holds thereafter. An incorrect assumption as it turns out.

While that is good advice, it can't apply to mutable input. Unless a defensive copy is made (at least, under the current system), concurrent modification can still occur. The new type's underlying data is still being accessed.

Re: Breaking java.lang.String

#137
post #124

Earlier quoted context omitted.

I can't agree with this analogy. This is not a defective user implementation of hashcode; it is a defective platform implementation of equals (and starts with, etc.).

A proper implementation of hashcode can return nonsense if you mutate the object during hashing.

Sure, but here we're not mutating the object during the String.startsWith() call. Hence I'd say it's a TOCTOU bug in String.valueOf().

Re: Breaking java.lang.String

#138
post #60
post #16

Earlier quoted context omitted.

Java definitely does "you wrote thread dangerous code, so it's your fault" for APIs not marked as being thread safe.

For what it's worth, Java does at least give some guarantees in case of data races -- the observed value will always be one that was explicitly set by one thread. This is different from most other languages, e.g. in C,C++, unsafe Rust it is UB. Of course it can and still will result in invalid states.

If you read a double or long while writing to it from another thread, you are not guaranteed to read a value that was ever explicitly set because they update 32 bits at a time rather than atomically.

Re: Breaking java.lang.String

#139

Earlier quoted context omitted.

> 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?

Yes. Java promises (unlike C, C++, Go, etc.) not to have Undefined Behaviour as a result of data races, however you do lose Sequential Consistency, which means humans aren't able to successfully reason about non-trivial 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 som…

Purely out of curiosity, is that much better? At least the data won't be complete garbage, but there'll still be a logic bug lurking in the details.

Re: Breaking java.lang.String

#140
I enjoyed the article, but if I may express a peeve of mine... In the code listings, can we please not use a syntax coloring scheme that makes the comments nearly unreadable? Especially in blog posts like this, where the code deliberately contains numerous explanatory comments. Such low-contrast text slows down my tired old eyes.
Post reply on HN