1 /* 2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8066103 27 * @summary C2's range check smearing allows out of bound array accesses 28 * @library /testlibrary /test/lib / 29 * @modules java.base/jdk.internal.misc 30 * java.management 31 * @build TestRangeCheckSmearing 32 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 33 * jdk.test.lib.Platform 34 * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 35 * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing 36 * 37 */ 38 39 import java.lang.annotation.*; 40 import java.lang.reflect.*; 41 import java.util.*; 42 import sun.hotspot.WhiteBox; 43 import sun.hotspot.code.NMethod; 44 import jdk.test.lib.Platform; 45 import compiler.whitebox.CompilerWhiteBoxTest; 46 47 public class TestRangeCheckSmearing { 48 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 49 50 @Retention(RetentionPolicy.RUNTIME) 51 @interface Args { int[] value(); } 52 53 // first range check is i + max of all constants 54 @Args({0, 8}) 55 static int m1(int[] array, int i, boolean allaccesses) { 56 int res = 0; 57 res += array[i+9]; 58 if (allaccesses) { 59 res += array[i+8]; 60 res += array[i+7]; 61 res += array[i+6]; 62 res += array[i+5]; 63 res += array[i+4]; 64 res += array[i+3]; 65 res += array[i+2]; 66 res += array[i+1]; 67 } 68 return res; 69 } 70 71 // first range check is i + min of all constants 72 @Args({0, -9}) 73 static int m2(int[] array, int i, boolean allaccesses) { 74 int res = 0; 75 res += array[i+1]; 76 if (allaccesses) { 77 res += array[i+2]; 78 res += array[i+3]; 79 res += array[i+4]; 80 res += array[i+5]; 81 res += array[i+6]; 82 res += array[i+7]; 83 res += array[i+8]; 84 res += array[i+9]; 85 } 86 return res; 87 } 88 89 // first range check is not i + min/max of all constants 90 @Args({0, 8}) 91 static int m3(int[] array, int i, boolean allaccesses) { 92 int res = 0; 93 res += array[i+3]; 94 if (allaccesses) { 95 res += array[i+2]; 96 res += array[i+1]; 97 res += array[i+4]; 98 res += array[i+5]; 99 res += array[i+6]; 100 res += array[i+7]; 101 res += array[i+8]; 102 res += array[i+9]; 103 } 104 return res; 105 } 106 107 @Args({0, -9}) 108 static int m4(int[] array, int i, boolean allaccesses) { 109 int res = 0; 110 res += array[i+3]; 111 if (allaccesses) { 112 res += array[i+4]; 113 res += array[i+1]; 114 res += array[i+2]; 115 res += array[i+5]; 116 res += array[i+6]; 117 res += array[i+7]; 118 res += array[i+8]; 119 res += array[i+9]; 120 } 121 return res; 122 } 123 124 @Args({0, -3}) 125 static int m5(int[] array, int i, boolean allaccesses) { 126 int res = 0; 127 res += array[i+3]; 128 res += array[i+2]; 129 if (allaccesses) { 130 res += array[i+1]; 131 res += array[i+4]; 132 res += array[i+5]; 133 res += array[i+6]; 134 res += array[i+7]; 135 res += array[i+8]; 136 res += array[i+9]; 137 } 138 return res; 139 } 140 141 @Args({0, 6}) 142 static int m6(int[] array, int i, boolean allaccesses) { 143 int res = 0; 144 res += array[i+3]; 145 res += array[i+4]; 146 if (allaccesses) { 147 res += array[i+2]; 148 res += array[i+1]; 149 res += array[i+5]; 150 res += array[i+6]; 151 res += array[i+7]; 152 res += array[i+8]; 153 res += array[i+9]; 154 } 155 return res; 156 } 157 158 @Args({0, 6}) 159 static int m7(int[] array, int i, boolean allaccesses) { 160 int res = 0; 161 res += array[i+3]; 162 res += array[i+2]; 163 res += array[i+4]; 164 if (allaccesses) { 165 res += array[i+1]; 166 res += array[i+5]; 167 res += array[i+6]; 168 res += array[i+7]; 169 res += array[i+8]; 170 res += array[i+9]; 171 } 172 return res; 173 } 174 175 @Args({0, -3}) 176 static int m8(int[] array, int i, boolean allaccesses) { 177 int res = 0; 178 res += array[i+3]; 179 res += array[i+4]; 180 res += array[i+2]; 181 if (allaccesses) { 182 res += array[i+1]; 183 res += array[i+5]; 184 res += array[i+6]; 185 res += array[i+7]; 186 res += array[i+8]; 187 res += array[i+9]; 188 } 189 return res; 190 } 191 192 @Args({6, 15}) 193 static int m9(int[] array, int i, boolean allaccesses) { 194 int res = 0; 195 res += array[i+3]; 196 if (allaccesses) { 197 res += array[i-2]; 198 res += array[i-1]; 199 res += array[i-4]; 200 res += array[i-5]; 201 res += array[i-6]; 202 } 203 return res; 204 } 205 206 @Args({3, 12}) 207 static int m10(int[] array, int i, boolean allaccesses) { 208 int res = 0; 209 res += array[i+3]; 210 if (allaccesses) { 211 res += array[i-2]; 212 res += array[i-1]; 213 res += array[i-3]; 214 res += array[i+4]; 215 res += array[i+5]; 216 res += array[i+6]; 217 } 218 return res; 219 } 220 221 @Args({3, -3}) 222 static int m11(int[] array, int i, boolean allaccesses) { 223 int res = 0; 224 res += array[i+3]; 225 res += array[i-2]; 226 if (allaccesses) { 227 res += array[i+5]; 228 res += array[i+6]; 229 } 230 return res; 231 } 232 233 @Args({3, 6}) 234 static int m12(int[] array, int i, boolean allaccesses) { 235 int res = 0; 236 res += array[i+3]; 237 res += array[i+6]; 238 if (allaccesses) { 239 res += array[i-2]; 240 res += array[i-3]; 241 } 242 return res; 243 } 244 245 // check that identical range check is replaced by dominating one 246 // only when correct 247 @Args({0}) 248 static int m13(int[] array, int i, boolean ignore) { 249 int res = 0; 250 res += array[i+3]; 251 res += array[i+3]; 252 return res; 253 } 254 255 @Args({2, 0}) 256 static int m14(int[] array, int i, boolean ignore) { 257 int res = 0; 258 259 res += array[i]; 260 res += array[i-2]; 261 res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check 262 res += array[i-1]; // range check removed so i-1 array access depends on previous check 263 264 return res; 265 } 266 267 static int[] m15_dummy = new int[10]; 268 @Args({2, 0}) 269 static int m15(int[] array, int i, boolean ignore) { 270 int res = 0; 271 res += array[i]; 272 273 // When the loop is optimized out we don't want the 274 // array[i-1] access which is dependent on array[i]'s 275 // range check to become dependent on the identical range 276 // check above. 277 278 int[] array2 = m15_dummy; 279 int j = 0; 280 for (; j < 10; j++); 281 if (j == 10) { 282 array2 = array; 283 } 284 285 res += array2[i-2]; 286 res += array2[i]; 287 res += array2[i-1]; // range check removed so i-1 array access depends on previous check 288 289 return res; 290 } 291 292 @Args({2, 0}) 293 static int m16(int[] array, int i, boolean ignore) { 294 int res = 0; 295 296 res += array[i]; 297 res += array[i-1]; 298 res += array[i-1]; 299 res += array[i-2]; 300 301 return res; 302 } 303 304 @Args({2, 0}) 305 static int m17(int[] array, int i, boolean ignore) { 306 int res = 0; 307 308 res += array[i]; 309 res += array[i-2]; 310 res += array[i-2]; 311 res += array[i+2]; 312 res += array[i+2]; 313 res += array[i-1]; 314 res += array[i-1]; 315 316 return res; 317 } 318 319 static public void main(String[] args) { 320 if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { 321 throw new AssertionError("Background compilation enabled"); 322 } 323 new TestRangeCheckSmearing().doTests(); 324 } 325 boolean success = true; 326 boolean exception = false; 327 final int[] array = new int[10]; 328 final HashMap<String,Method> tests = new HashMap<>(); 329 { 330 final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class }; 331 for (Method m : this.getClass().getDeclaredMethods()) { 332 if (m.getName().matches("m[0-9]+")) { 333 assert(Modifier.isStatic(m.getModifiers())) : m; 334 assert(m.getReturnType() == int.class) : m; 335 assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m; 336 tests.put(m.getName(), m); 337 } 338 } 339 } 340 341 void invokeTest(Method m, int[] array, int index, boolean z) { 342 try { 343 m.invoke(null, array, index, z); 344 } catch (ReflectiveOperationException roe) { 345 Throwable ex = roe.getCause(); 346 if (ex instanceof ArrayIndexOutOfBoundsException) 347 throw (ArrayIndexOutOfBoundsException) ex; 348 throw new AssertionError(roe); 349 } 350 } 351 352 void doTest(String name) { 353 Method m = tests.get(name); 354 tests.remove(name); 355 int[] args = m.getAnnotation(Args.class).value(); 356 int index0 = args[0], index1; 357 boolean exceptionRequired = true; 358 if (args.length == 2) { 359 index1 = args[1]; 360 } else { 361 // no negative test for this one 362 assert(args.length == 1); 363 assert(name.equals("m13")); 364 exceptionRequired = false; 365 index1 = index0; 366 } 367 // Get the method compiled. 368 if (!WHITE_BOX.isMethodCompiled(m)) { 369 // If not, try to compile it with C2 370 if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { 371 // C2 compiler not available, try to compile with C1 372 WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); 373 } 374 } 375 if (!WHITE_BOX.isMethodCompiled(m)) { 376 throw new RuntimeException(m + " not compiled"); 377 } 378 379 // valid access 380 invokeTest(m, array, index0, true); 381 382 if (!WHITE_BOX.isMethodCompiled(m)) { 383 throw new RuntimeException(m + " deoptimized on valid array access"); 384 } 385 386 exception = false; 387 boolean test_success = true; 388 try { 389 invokeTest(m, array, index1, false); 390 } catch(ArrayIndexOutOfBoundsException aioob) { 391 exception = true; 392 System.out.println("ArrayIndexOutOfBoundsException thrown in "+name); 393 } 394 if (!exception) { 395 System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name); 396 } 397 398 if (Platform.isServer()) { 399 if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) { 400 System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name); 401 test_success = false; 402 } 403 } 404 405 if (exception != exceptionRequired) { 406 System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name); 407 test_success = false; 408 } 409 410 if (!test_success) { 411 success = false; 412 System.out.println("TEST FAILED: "+name); 413 } 414 415 } 416 void doTests() { 417 doTest("m1"); 418 doTest("m2"); 419 doTest("m3"); 420 doTest("m4"); 421 doTest("m5"); 422 doTest("m6"); 423 doTest("m7"); 424 doTest("m8"); 425 doTest("m9"); 426 doTest("m10"); 427 doTest("m11"); 428 doTest("m12"); 429 doTest("m13"); 430 doTest("m14"); 431 doTest("m15"); 432 doTest("m16"); 433 doTest("m17"); 434 if (!success) { 435 throw new RuntimeException("Some tests failed"); 436 } 437 assert(tests.isEmpty()) : tests; 438 } 439 }