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

最近、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



ます。



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



All Articles