1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.reflect.Field; 18 19 public class Main { main(String[] args)20 public static void main(String[] args) throws Exception { 21 if (!isDalvik) { 22 // This test is ART-specific. Just fake the expected output. 23 System.out.println("JNI_OnLoad called"); 24 return; 25 } 26 System.loadLibrary(args[0]); 27 if (!hasJit()) { 28 return; 29 } 30 testValueOfArg(); 31 testValueOfConst(); 32 } 33 testValueOfArg()34 public static void testValueOfArg() throws Exception { 35 final VolatileFlag start_end = new VolatileFlag(); 36 Thread t = new Thread() { 37 @Override 38 public void run() { 39 try { 40 Class<?> integerCacheClass = Class.forName("java.lang.Integer$IntegerCache"); 41 Field cacheField = integerCacheClass.getDeclaredField("cache"); 42 cacheField.setAccessible(true); 43 44 Integer[] cache = (Integer[]) cacheField.get(integerCacheClass); 45 Integer[] alt_cache = new Integer[cache.length]; 46 System.arraycopy(cache, 0, alt_cache, 0, cache.length); 47 48 // Let the main thread know that everything is set up. 49 synchronized (start_end) { 50 start_end.notify(); 51 } 52 while (!start_end.flag) { 53 cacheField.set(integerCacheClass, alt_cache); 54 cacheField.set(integerCacheClass, cache); 55 } 56 } catch (Throwable t) { 57 throw new Error(t); 58 } 59 } 60 }; 61 synchronized (start_end) { 62 t.start(); 63 start_end.wait(); // Wait for the thread to start. 64 } 65 // Previously, this may have used an invalid IntegerValueOfInfo (because of seeing 66 // the `alt_cache` which is not in the boot image) when asked to emit code after 67 // using a valid info (using `cache`) when requesting locations. 68 ensureJitCompiled(Main.class, "getAsInteger"); 69 70 start_end.flag = true; 71 t.join(); 72 73 Runtime.getRuntime().gc(); // Collect the `alt_cache`. 74 75 // If `getAsInteger()` was miscompiled, it shall try to retrieve an Integer reference 76 // from a collected array (low = 0, high = 0 means that this happens only for value 0), 77 // reading from a bogus location. Depending on the GC type, this bogus memory access may 78 // yield SIGSEGV or `null` or even a valid reference. 79 Integer new0 = getAsInteger(0); 80 int value = (int) new0; 81 82 if (value != 0) { 83 throw new Error("value is " + value); 84 } 85 } 86 testValueOfConst()87 public static void testValueOfConst() throws Exception { 88 Class<?> integerCacheClass = Class.forName("java.lang.Integer$IntegerCache"); 89 Field cacheField = integerCacheClass.getDeclaredField("cache"); 90 cacheField.setAccessible(true); 91 Field lowField = integerCacheClass.getDeclaredField("low"); 92 lowField.setAccessible(true); 93 94 Integer[] cache = (Integer[]) cacheField.get(integerCacheClass); 95 int low = (int) lowField.get(integerCacheClass); 96 Integer old42 = cache[42 - low]; 97 cache[42 - low] = new Integer(42); 98 99 // This used to hit 100 // DCHECK(boxed != nullptr && 101 // Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed)); 102 // when compiling the intrinsic. 103 ensureJitCompiled(Main.class, "get42AsInteger"); 104 105 cache[42 - low] = old42; 106 Runtime.getRuntime().gc(); 107 Integer new42 = get42AsInteger(); 108 109 // If the DCHECK() was removed, MterpInvokeVirtualQuick() used to crash here. 110 // (Note: Our fault handler on x86-64 then also crashed.) 111 int value = (int) new42; 112 113 if (value != (int) old42) { 114 throw new Error("value is " + value); 115 } 116 } 117 118 private static class VolatileFlag { 119 public volatile boolean flag = false; 120 } 121 get42AsInteger()122 public static Integer get42AsInteger() { 123 return Integer.valueOf(42); 124 } 125 getAsInteger(int value)126 public static Integer getAsInteger(int value) { 127 return Integer.valueOf(value); 128 } 129 hasJit()130 private native static boolean hasJit(); ensureJitCompiled(Class<?> itf, String method_name)131 private static native void ensureJitCompiled(Class<?> itf, String method_name); 132 133 private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik"); 134 } 135