Press enter to see results or esc to cancel.

Riddles in the Dark

Hello and welcome to another post about the JVM internals! However, this one is going to be slightly different and here is why:

We’ve recently participated in JBreak 2018, a Java conference held right in our home city of Novosibirsk, Russia1. One of our colleagues, Nikita Lipsky, gave a brilliant talk about bytecode verification and others were representing Excelsior at the exhibition. Among the activities at our stand, we had a list of tricky questions about the inner workings of the JVM. Solving that quiz, visitors could feel themselves in a JVM engineer’s shoes for a moment. We had many vivid discussions about our quiz at the conference, and now want to present it to you along with detailed answers to all questions. So, sit back, relax and prepare to some riddles in the dark..

#1 Understanding Weak Refs

Problem: Consider the following code snippet:

void playWithRef() {
    Object obj = new Object();
    WeakReference ref = new WeakReference<>(obj);
    System.out.println(ref.get() != null);
    System.gc();
    System.out.println(ref.get() != null);
}

and specify its possible output(s). Note that there can be multiple correct answers to this and some other problems!

  1. falsefalse
  2. falsetrue
  3. truefalse
  4. truetrue

#2 Classfile Puzzle

Problem: This one is a classical puzzle where you have to build a picture from small pieces. Here is a hex dump of some Java .class file that had its lines shuffled by accident:

A. 0700 0401 0001 4300 2000 0300 0100 0000
B. 0000 0000 00
C. 6a61 7661 2f6c 616e 672f 4f62 6a65 6374
D. cafe babe 0000 0031 0005 0700 0201 0010

Your goal is to put these lines in the right order so as to reconstruct a verifiable .class file.

#3 Invert a Boolean

Problem: In the next riddle, you can try yourself at native code generation! Let’s start with something small. Consider the following method:

static boolean invert(boolean x) {
    return !x;
}

Which of the (Intel x86 Assembly) code snippets below are the correct native implementations of this method?

A:      test ecx, ecx
        jnz True
        mov eax, 1
        ret
True:   mov eax, 0
        ret
B:      xor eax, eax
        test ecx, ecx
        jnz End
        add eax, 1
End:    ret
C:      mov eax, 1
        sub eax, ecx
        ret
D:      mov eax, ecx
        xor eax, 1
        ret

(In all snippets the argument is passed on the ecx register and the result is returned on eax.)

#4 The Interface Is a Lie

Problem: Imagine that you have found the following method in someone else’s code:

void guessWhat(Iterable<?> x) {
    System.out.println(x.getClass());
}

Can you guess what this method might possibly print?

  1. class java.util.ArrayList
  2. null
  3. interface java.lang.Iterable
  4. class java.lang.Integer

#5 Slipping under the Radar

Problem: Given the following source code:

class C {
    private boolean getBoolean() {
        return false;
    }
}

interface I {
    default boolean getBoolean() {
        return true;
    }
}

class D extends C implements I {}

public class Test {
    public static void main(String[] a) {
        foo(new D());
    }

    public static void foo(I i) {
        System.out.println(i.getBoolean());
    }
}

what do you think will this program do if you compile it and run the class Test?

  1. Won’t compile
  2. Throw java.lang.IllegalAccessError
  3. Print true
  4. Print false

#6 Implicit Exceptions

Problem: You’ve been debugging a Java application for a while. Unfortunately, you have no source code or .class file, only the listing of generated assembly code. The good news is that you’ve already found the problematic method:

lea  rax, [rel _Test_foo]
push rax
mov  eax, dword [rcx+0FH]
idiv dword [rdx+0FH]
mov  rbx, qword [rel _Test_array]
mov  ebx, dword [rbx+3BH]
add  eax, ebx
ret  8

You are pretty sure that some Java exceptions can be thrown out of this method. So, the last step is to understand which instructions can provoke Java exceptions of the following types:

StackOverflowError: __

NullPointerException: __

ArithmeticException: __

IndexOutOfBoundsException: __

#7 When Verification Fails

Problem: Whether due to bit rot or malicious actions, but the Helper.class file has changed so that the end of the method sayC() is no longer verifiable:

public class Main {
    public static void main(String[] args) {
        System.out.print("A");
        Helper.sayB();
        Helper.sayC();
    }
}

public class Helper {
    public static void sayB() {
        System.out.print("B");
    }

    public static void sayC() {
        System.out.print("C");
        // bad bytecode goes here
    }
}

What will the program do if you run the class Main?

  1. Throw a VerifyError
  2. Print “A” and throw a VerifyError
  3. Print “AB” and throw a VerifyError
  4. Print “ABC” and throw a VerifyError

So, that’s it! We’ve got dozens of solutions and held many discussions with our stand visitors at the conference. Assembly listings confused some of them a little bit (it was a Java conference after all!), but in general the immediate feedback was positive. And what is your take on our quiz? Which question is the most interesting, in your opinion? Tell us in comments section here, or join the discussion on Reddit and/or HackerNews!

Footnotes

  1. Since the conference took place in Russia, we’ve also published a Russian version of this post.