Time Travel with JVM
Let’s repeat an ancient mistake:
Our Date
abstraction is supposed to mimic the infamous java.util.Date
class. Unless we’ve cracked the time travel problem or our clock is way off, the getTimestamp()
method should never return 0, right?
“First Step”
Let’s declare an instance of this Date
class like a normal human being:
In my machine, in this very moment of writing, this prints:
Sounds plausible!
“Afraid of Time”
This time around, the sun.misc.Unsafe
holds the Answer to the Ultimate Question of Life, the Universe, and Everything:
Let’s create an instance of Date
via Unsafe.allocateInstance(Class<?> clazz)
method:
Quite surprisingly, this will print 0
, because the allocateInstance
method bypasses the Java constructor!
By now one might question the integrity of the whole Java platform regarding final
fields!
“What Happens Now?”
Here’s what happens when we instantiate a new object instance via new
keyword in Java:
- At first, JVM tries to find a place for that new object in its process space.
- Then it executes the System Initialization process. In this phase, the newly created object would be initialized with its default values. For example, the
timestamp
value would be0
at this stage. - Finally, it calls the instance initializer and constructors. In this case, the constructor changes the
timestamp
value to the current epoch time.
For instance, the following code:
Translates to the following bytecode
The first part, i.e. 0: new #2 // class me/alidg/Date
, represents the system initialization phase. Additionally, the invokespecial
is responsible for calling the constructor.
When using Unsafe
, on the contrary, the constructor call would be skipped. Therefore, the Date
instance would be initialized with its default values, enabling us to travel back in time!
“No Time for Caution”
If we try to compile any code that exploits the Unsafe
class, we might get the following warning from javac
:
So stay away from Unsafe
.