ボクシング時のやや予期しないキャッシュ動作

最近、The Daily WTF 、Reflectionが同僚の良い血を台無しにするのにどのように役立つかについて書いています。

次のコードがあるとしましょう:

public class ConstantHolder { public static final Integer THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42; } 
そして
 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); } } 


明らかにtrueが出力されます。 ただし、プロジェクトには、状況を逆方向に変更できるようなコードが含まれている場合があります。 猫の下はそのようなコードの例です。


ConstantHolderクラス(またはロードされる別のクラス)に次のコードを追加するだけで十分です。

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


その後、プログラムの出力はfalse変わりfalse

なぜそう


ご覧のとおり、定数はInteger型で、テストクラスのローカル変数はint型です。 int Integerに割り当てようとすると、 valueフィールドはInteger -aから読み取られ、リフレクションを使用して別の値を割り当てるため、ユーザーが期待するものは読み取られません。

あなたが推測できるように、コードのエントリが他のどこかにある場合
 Integer someInteger = 42; 
そして、このsomeIntegerが使用され、その値はboxing / anboxing中のキャッシュにより同じ9000になります。 つまり、 Integer.valueOf(anInt)は、特定のanInt値に対して同じオブジェクトをanIntます。

これに対抗する方法はなく、ありそうもない。 注意して、同僚を怒らせないでください:)

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


All Articles