CrossLangFuzzer: Differential Testing of Cross-Language JVM Compilers
This paper introduces CrossLangFuzzer, the first differential testing framework that leverages the Kotlin compiler's unified intermediate representation and mutation operators to synthesize cross-language test programs, successfully uncovering 32 confirmed bugs across five major JVM compilers.
Original paper licensed under CC BY 4.0 (http://creativecommons.org/licenses/by/4.0/). This is an AI-generated explanation of the paper below. It is not written or endorsed by the authors. For technical accuracy, refer to the original paper. Read full disclaimer
Imagine the Java Virtual Machine (JVM) as a massive, bustling international airport. In this airport, different airlines (programming languages like Java, Kotlin, Scala, and Groovy) all land on the same runways and use the same control towers. Usually, they get along fine. But sometimes, an airline from one country tries to hand a passenger off to an airline from another country, and the handoff goes wrong because their rules for "boarding passes" (types) or "luggage limits" (nullability) are slightly different.
When these handoffs fail, the plane might crash, or worse, it might take off with the wrong passengers on board, leading to chaos later. These are called miscompilations.
The Problem: The "Silent Handoff"
The authors of this paper noticed that while we have excellent tools to test how well a single airline operates (testing Java alone, or Kotlin alone), we don't have good tools to test what happens when they interact.
Think of it like this: You might have a perfect test for how a pilot flies a plane in clear weather. But you haven't tested what happens when that pilot has to talk to a pilot from a different airline who uses a different radio frequency. If the instructions get garbled during the conversation, the plane might crash. Existing tests were ignoring these "conversations" between languages.
The Solution: CrossLangFuzzer
The team built a tool called CrossLangFuzzer. You can think of this tool as a super-robotic translator and prankster designed specifically to break these handoffs.
Here is how it works, step-by-step:
The Universal Blueprint (The IR):
Instead of writing code in Java or Kotlin directly, the robot first draws a "Universal Blueprint" (called an Intermediate Representation or IR). This blueprint is like a master architectural drawing that doesn't care if the final building is made of brick (Java) or wood (Kotlin). It just knows the structure: "Here is a door, here is a window, here is a roof."The Translator (The Printer):
The robot takes this Universal Blueprint and instantly prints it out as real code in multiple languages at once. It might print a Java version, a Kotlin version, and a Scala version of the exact same logical structure.The Prankster (The Mutator):
This is the fun part. The robot has a set of seven "prank" moves. It takes the blueprint and deliberately twists it in ways that are tricky for the compilers to handle.- Analogy: Imagine it takes a sentence like "The cat sat on the mat" and swaps "cat" with "dog," or changes "sat" to "jumped," or adds a question mark where it shouldn't be.
- It does this to the types and rules (like making a number optional or changing a generic list). It's trying to confuse the compilers: "Hey, does this still make sense to you?"
The Referee (Differential Testing):
The robot sends these twisted programs to the actual compilers (the control towers).- Scenario A: Compiler A says, "This is fine!" and Compiler B says, "Error! This is broken!"
- Scenario B: Compiler A crashes, but Compiler B keeps running.
- The Verdict: If the compilers disagree on whether the code is valid, the robot flags it as a bug. It's like two referees blowing whistles for different reasons on the same play.
The Detective (The Reducer):
When a bug is found, the test program might be huge and complicated. The robot acts like a detective, stripping away parts of the code one by one to find the smallest possible piece that still causes the crash. This makes it easy for the human developers to look at the code and say, "Ah, yes, I see the problem here."
The Results
The team tested this robot against the five biggest "airlines" in the JVM world: Java, Kotlin, Scala (versions 2 and 3), and Groovy.
The robot found 32 confirmed bugs.
- It found 15 bugs in Kotlin.
- 7 in Scala 3.
- 4 in Groovy.
- 4 in Java.
- 2 in Scala 2.
Crucially, these weren't just theoretical problems. The developers of these languages confirmed the bugs. In fact, the Groovy team fixed 100% of the bugs the robot found, and the Kotlin team has already fixed one, with the rest confirmed and waiting for patches.
Why This Matters
The paper argues that as software becomes more complex and mixes different languages together, we can't just test them in isolation anymore. We need a tool that specifically looks at the messy, confusing boundaries where these languages meet. CrossLangFuzzer is the first tool to do this systematically, acting as a stress-test for the "handoffs" in the JVM ecosystem to keep the planes flying safely.
Drowning in papers in your field?
Get daily digests of the most novel papers matching your research keywords — with technical summaries, in your language.