DEV Community

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

Posted on

1

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!

Great read:

Is it Time to go Back to the Monolith?

History repeats itself. Everything old is new again and I’ve been around long enough to see ideas discarded, rediscovered and return triumphantly to overtake the fad. In recent years SQL has made a tremendous comeback from the dead. We love relational databases all over again. I think the Monolith will have its space odyssey moment again. Microservices and serverless are trends pushed by the cloud vendors, designed to sell us more cloud computing resources.

Microservices make very little sense financially for most use cases. Yes, they can ramp down. But when they scale up, they pay the costs in dividends. The increased observability costs alone line the pockets of the “big cloud” vendors.

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay