It has been great to see the paper making rounds in industrial circles, but there also seems to be a lot of confusion and I think that’s our fault. The paper was written for academics, and so it doesn’t discuss the issue from industry’s perspective.
I’m crunching on a deadline right now, so let me write an abridged version of the industry-targeted paper here, focusing just on Java. Most type systems aim to provide some sort of guarantee about how a well-type program will behave.
For example, in many languages all memory accesses are “safe” in well-typed programs. A type system is sound if it actually succeeds at providing that guarantee.
Thus, both of these examples seem like they allow one to contain an Integer despite the fact that it is declared to have type String. The designers intended the type system to allow this behavior.
Every time you assign a value into an array (of a reference type), the runtime looks up the array value’s actual element type and throws an ArrayStoreException if it’s incompatible. Similarly, whenever get is called on a List
And since generics were introduced, it was believed to be “truly” sound so long as you didn’t use these intentional backdoors. Here’s our “true” unsoundness example that has been making the rounds most recently.
According to the Java specification, this program is well-typed, and according to the Java specification it should execute without exception (unlike the aforementioned backdoors) and actually assign the Integer instance to the String variable, violating the intended behavior of well-typed programs. Thus, it illustrates that Java’s type system is unsound.
If your compiler does type check it, and then you run it, you get a ClassCastException, also contradicting my claim. The Java specification says this example should type check and compile.
It’s failing because it didn’t anticipate the corner case we created here. A good programmer is supposed to anticipate and handle corner cases, not just excuse a bug because it is hard to create.
So even if this bug turns out to be low priority, which I’ll get to in a bit, it’s still important to know it exists. This secret check is done for backwards compatibility with raw types.
Instead, I could cast anything into an int and get direct access to the raw bytes of many objects, which I could then use to inject arbitrary code (using return-oriented programming to bypass security measures). I in fact do this all the time ; it’s a huge part of my research agenda.
What matters is if someone can write this, because then that someone can get around the security measures that people have placed their confidence in and do whatever they would like to do. In the case of soundness, it’s the malicious programmer you should be worried, not just you and your friends.
It’s actually faulty reasoning that’s been around in both industry and academia for at least as long as I’ve been out of high school (which has been a while). The conventional wisdom up until now, and probably your gut instinct, would say this is unsafe, since it turns a String into a Number, but the fact is that it’s completely safe.
For any class with a constrained type parameter, I can just make a corresponding interface without that constraint and use that throughout the program. Thus, the seemingly unsafe invocation of foo in bar will never happen because you can’t invoke a method of an object that can never exist.
You’ll only ever be able to have an instance of it if T is a subtype of U at run time, satisfying the constraint. I found out that, although uncommon, this implicit constraints are in fact used for type-checking a number of Java libraries.
The paper gives a specific example showing why implicit constraints are important. Consequently, it infers X to be the type argument to bind. Upcast and uses its explicit and implicit constraints to type-check the rest of the invocation.
The reasoning for wildcard capture completely forgets about null pointers. It assumes there must be some actuals Constrain for some X, an assumption that manifests itself in the implicit constraint on X.
Oh, and it’s also not nearly as easy to fix as most null-pointer bugs, since every feature involved is used in practice. Super T> type, realize that that kind of reasoning is what delayed core Scala’s proof of soundness (without null) for a whole decade, and I’m not particularly eager to spend a decade solving this.
We are now accepting submissions and happy to discuss advertising sponsorship opportunities. To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon. Tags Join Hacker Noon Create your free account to unlock your custom reading experience.
We provide the three programs as listed in the paper (Amino and Tate, OOPS LA'16 forthcoming), and step-by-step instructions on how to compile and run them. These short programs demonstrate the unsoundness of Java and Scala’s current type systems.
Fortunately, parametric polymorphism was not integrated into the Java Virtual Machine (JVM), so these examples do not demonstrate any unsoundness of the JVM You need to be able to use Java, java, scalar, Scala.
Step 2: Compile Note that Unsound. You can also switch back to an earlier JDK, e.g. 6, to try the steps with more previous versions of Scala (download list).
The earliest version we could get to work with JDK 8 is 2.10.2, and all the releases we sampled in between up to the current milestone 2.12.0-M4 reproduce the remaining steps. The example does not compile in Scala 2.9.3 and earlier due to restrictions on dependent method types.
We submitted the finding and related discussion to OOPS LA, an academic confer... Biomass Kids, an undergraduate student in the University of Tokyo, has found the problem below in the implementation of generics in Java.
Here is my understanding (confirmed by At sushi Karachi) of the problem: after erasure (i.e., replacing every type variable with the Object class), an auxiliary method (called bridged method) like However, this additional method happens to override A.compared and raises an unexpected ClassCastException.
This is a fascinating problem, because it is not only a bug or an oversight in the compiler, it is not only a problem with the language design and erasure, it completely changes the subtyping relation for Java ! Just as much as the compiler should have recognized the result of creating the bridge method, the language design using erasure is at fault.
Java’s erasure makes it impossible to throw gentrified exceptions! I must admit that a couple of years ago, I couldn’t quite understand what was so bad about erasure.