Spaghetti and Hammers

When 1 + 1 = 3

When 1 + 1 = 3

March 24, 2020 | 2 Minute Read

I was looking at some old gists of mine yesterday and I found one that I thought it was worth sharing. It’s not something new for anyone who has been using Java for some time probably, but it’s one of those things newcomers get amazed every time.

For this we are going to use the ‘new’ java REPL (you need java 9 or newer) as it’s easier than setting up a full maven/gradle project.

So, in what consists this ‘trick’ we are talking about? You are probably familiar with the expression 1 + 1 = 2 right? Which is usually applied to explain simple situations.

Well, Java says otherwise…

jshell> 1 + 1
$6 ==> 3

And how is this possible? To understand how this works, we need to get a bit into the internals of the Integer class.

The current Integer class implementation contains a cache, which was introduced to save memory and to improve performance for Integer type objects handlings. Integer instances are cached and reused. The blog Javapapers has an excellent article on the topic. It’s a quick read, and it will explain IntegerCache much better than me :)

Now back to our little dark magic. The trick here is to mess with the IntegerCache through reflection. By changing the cache value for a given int, you will be able to do all sort of hacks.

$ jshell
|  Welcome to JShell -- Version 11.0.2
|  For an introduction type: /help intro

jshell> import java.lang.reflect.Field;

jshell> Field value = Integer.class.getDeclaredField("value");
value ==> private final int java.lang.Integer.value

jshell> value.setAccessible(true);

jshell> value.set(2, 3);

jshell> 1 + 1
$6 ==> 3

And voilá, you are now a professional hacker. But…

jshell> value.set(129, 130);

jshell> 129
$8 ==> 129

Why is 129 returning 129 instead of 130? If you read the article I mentioned, there’s one important detail:

The Javadoc comment clearly states that this class is for cache and to support the autoboxing of values between 128 and 127.

So this trick only works for smaller numbers (actually, the high value of 127 can be modified by using a VM argument -XX:AutoBoxCacheMax=<size>.)

Some other java classes also allow you to hack them. Just have fun exploring :)

jshell> Field v = String.class.getDeclaredField("value");
v ==> private final byte[] java.lang.String.value

jshell> v.setAccessible(true);

jshell> String s = "hello!";
s ==>

jshell> v.set(s, "cheers" .getBytes());

jshell> System.out.println(s);
cheers

Newsletter

Did you enjoy this blog post? Sign up for my Newsletter to be notified of new posts. (Pretty low-volume, around once per month.)