📜 ⬆️ ⬇️

Somewhat unexpected caching behavior when boxing

Recently, The Daily WTF wrote about how using Reflection can be a good idea to spoil the blood of colleagues.

Suppose you have the following code:

public class ConstantHolder { public static final Integer THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42; } 
and
 public class TestBoxingVulnerability { public static void main(String[] args) { int theAnswer = ConstantHolder.THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING; System.out.println(theAnswer == 42); } } 

')
Obviously, true will be displayed. However, the project may be such a code that can change the situation in the opposite direction. Under the cat is an example of such a code.


It is enough to add the following code to the ConstantHolder class (or to another class that will be loaded):

 static { //happy debugging try { Field field = Integer.class.getDeclaredField("value"); field.setAccessible(true); field.setInt(Integer.valueOf(42), 9000); } catch (Throwable t) {} } 


and after that the output of the program will change to false .

Why is that


As you can see, the constant is of type Integer , while the local variable in the testing class is of type int . When trying to assign an Integer to an int , the value field of Integer -a is read, and since we assigned another value to it using reflection, it does not read what the user expects.

As you can guess, if in the code in any other place there is a record like
 Integer someInteger = 42; 
and then this someInteger will be used, its value will be the same 9000 due to caching during boxing / unboxing . That is, Integer.valueOf(anInt) will return the same objects for certain anInt values.

There are no methods to combat this, and they are unlikely to be. Be careful not to offend your colleagues :)

Source: https://habr.com/ru/post/119895/


All Articles