DEV Community

João Paulo Martins Silva
João Paulo Martins Silva

Posted on

2 + 2 = 5 em Java 21

Há alguns anos, encontrei um vídeo do podcaster Lex Friedman em que ele demonstra que é possível fazer 2+2 ser cinco em Java usando alguns truques.


import java.lang.reflect.Field;   
    public class Main {
        public static void main(String[] args) throws Exception {
            Class cache = Integer.class.getDeclaredClasses()[0];
            Field c = cache.getDeclaredField("cache");
            c.setAccessible(true);
            Integer[] array = (Integer[]) c.get(cache);
            array[132] = array[133];

            System.out.printf("%d",2 + 2);
        }
    }

Enter fullscreen mode Exit fullscreen mode

Por curiosidade, resolvi rodar o código disponibilizado nos links do vídeo e me deparei com o seguinte erro:

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field static final java.lang.Integer[] java.lang.Integer$IntegerCache.cache accessible: module java.base does not "opens java.lang" to unnamed module @8efb846
 at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
 at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
 at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
 at Old2Plus2.main(Old2Plus2.java:7)
Enter fullscreen mode Exit fullscreen mode

Percebi que, para as novas versões do Java, esse hack não era mais possível. Portanto, neste artigo, irei demonstrar como realizar esse truque para o Java 21

A mensagem de erro diz que o módulo java.base não está aberto. Isso significa que não é possível usar reflexão a partir da classe Main criada para esse exemplo. Caso não tenha muita familiaridade com módulos, recomendo dar uma relembrada.

Ou seja, no Java 21, é mais difícil fazer esse tipo de hack com a linguagem. Felizmente, existe uma classe que nos permite negligenciar o sistema de módulos: a sun.misc.Unsafe. Essa classe é utilizada para executar operações de baixo nível e não é recomendada para o dia a dia de programadores comuns.

Sendo assim, a nova versão do código que faz 2+2 = 5 ficaria dessa forma:

import java.lang.reflect.Field;

public class New2Plus2 {
    public static void main(String[] args) throws Exception {
        Class usf = Class.forName("sun.misc.Unsafe");//pega o objeto que representa a classe Unsafe
        Field unsafeField = usf.getDeclaredField("theUnsafe");//pega o campo theUnsafe da classe Unsafe
        unsafeField.setAccessible(true);//define o campo theUnsafe como público
        sun.misc.Unsafe unsafe = (sun.misc.Unsafe)unsafeField.get(null);//pega o valor do campo theUnsafe, como ele é static é passado o parâmetro null
        Class<?> clazz = Class.forName("java.lang.Integer$IntegerCache");// pega o objeto que representa a classe IntegerCache
        Field field = clazz.getDeclaredField("cache");//pega o campo cache da classe IntegerCache
        Integer[] cache = (Integer[])unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));//utiliza a classe Unsafe para pegar o cache de Integer
        cache[132] = cache[133];// troca o valor 4 pelo 5
        System.out.printf("2+2 = %d",2 + 2);
    }
}
Enter fullscreen mode Exit fullscreen mode

Executando o código acima, você verá que o resultado da soma será 5. Obviamente, não recomendo utilizar esse código em produção se você quiser manter sua sanidade e seu emprego.

Referências:

https://github.com/joao9aulo/2plus2equals5

https://javax0.wordpress.com/2017/05/03/hacking-the-integercache-in-java-9/

https://www.youtube.com/watch?v=amXXYgu0eFY

https://ideone.com/o1h0hR

https://www.oracle.com/br/corporate/features/understanding-java-9-modules.html

https://www.baeldung.com/java-unsafe

Top comments (2)

Collapse
 
wldomiciano profile image
Wellington Domiciano

A nova versão do hack deu certinho!

Contudo, a versão anterior ainda funciona sem maiores problemas, vc só precisa usar as opções certas na hora de executar o programa.

A mensagem de erro diz que o módulo java.base não abre o pacote java.lang para o seu módulo sem nome.

Por isso precisamos usar a opção --add-opens. Esta opção permite sobrescrever as definições do módulo. O comando é o seguinte:

# Se vc for rodar em source-code mode
java --add-opens java.base/java.lang=ALL-UNNAMED Main.java

# Ou, para rodar do jeito tradicional
javac Main.java && java --add-opens java.base/java.lang=ALL-UNNAMED Main
Enter fullscreen mode Exit fullscreen mode
Collapse
 
joao9aulo profile image
João Paulo Martins Silva

Boa!