EarlyReturnNegativeTest.java revision 11884:b45c81ca8671
1/* 2 * Copyright (c) 2006, 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 6431735 27 * @summary Unexpected ClassCastException in ThreadReference.forceEarlyReturn 28 * @author Jim Holmlund 29 * 30 * @modules jdk.jdi 31 * @run build TestScaffold VMConnection TargetListener TargetAdapter 32 * @run compile -g EarlyReturnNegativeTest.java 33 * @run driver EarlyReturnNegativeTest 34 */ 35import com.sun.jdi.*; 36import com.sun.jdi.event.*; 37import com.sun.jdi.request.*; 38import java.util.*; 39import java.net.URLClassLoader; 40import java.net.URL; 41import java.lang.reflect.Array; 42 43/* 44 * This test has a debuggee which calls an instance method 45 * for each kind of JDI value return type. 46 * 47 * The debugger sets breakpoints in all methods. When a breakpoint 48 * is hit the debugger requests an early return and supplies a new 49 * return value. The new value is not compatible with the method's 50 * return type so an InvalidTypeException should be thrown. 51 * 52 * Each value is stored in a static var in the debuggee. The debugger 53 * gets the values from these static vars to pass back to the 54 * debuggee in forceEarlyReturn. 55 * 56 * This test was created out of EarlyReturnTest.java. Not all of the 57 * debuggee methods are actually used, just the ones needed to test 58 * for correct operation. I left the others in just in case they come 59 * in handy in the future. 60 */ 61 62class EarlyReturnNegativeTarg { 63 /* 64 * These are the values that will be used by methods 65 * returning normally. 66 */ 67 static URL[] urls = new URL[1]; 68 public static byte byteValue = 89; 69 public static char charValue = 'x'; 70 public static double doubleValue = 2.2; 71 public static float floatValue = 3.3f; 72 public static int intValue = 1; 73 public static long longValue = Long.MAX_VALUE; 74 public static short shortValue = 8; 75 public static boolean booleanValue = false; 76 77 public static Class classValue = Object.class; 78 public static ClassLoader classLoaderValue; 79 { 80 try { 81 urls[0] = new URL("hi there"); 82 } catch (java.net.MalformedURLException ee) { 83 } 84 classLoaderValue = new URLClassLoader(urls); 85 } 86 87 public static Thread threadValue = Thread.currentThread(); 88 public static ThreadGroup threadGroupValue = threadValue.getThreadGroup(); 89 public static String stringValue = "abc"; 90 public static int[] intArrayValue = new int[] {1, 2, 3}; 91 public static Object[] objectArrayValue = new Object[] {"a", "b", "c"}; 92 93 public static EarlyReturnNegativeTarg objectValue = 94 new EarlyReturnNegativeTarg(); 95 public String ivar = stringValue; 96 97 98 // Used to show which set of tests follows 99 public static String s_show(String p1) { return p1;} 100 101 // These are the instance methods 102 public byte i_bytef() { return byteValue; } 103 public char i_charf() { return charValue; } 104 public double i_doublef() { return doubleValue; } 105 public float i_floatf() { return floatValue; } 106 public int i_intf() { return intValue; } 107 public long i_longf() { return longValue; } 108 public short i_shortf() { return shortValue; } 109 public boolean i_booleanf() { return booleanValue; } 110 public String i_stringf() { return stringValue; } 111 public Class i_classf() { return classValue; } 112 public ClassLoader i_classLoaderf() 113 { return classLoaderValue; } 114 public Thread i_threadf() { return threadValue; } 115 public ThreadGroup i_threadGroupf() 116 { return threadGroupValue; } 117 public int[] i_intArrayf() { return intArrayValue; } 118 public Object[] i_objectArrayf() { return objectArrayValue; } 119 public Object i_nullObjectf() { return null; } 120 public Object i_objectf() { return objectValue; } 121 public void i_voidf() {} 122 123 static void doit(EarlyReturnNegativeTarg xx) throws Exception { 124 System.err.print("debugee in doit "); 125 126 s_show("========== Testing instance methods ================"); 127 xx.i_bytef(); 128 xx.i_charf(); 129 xx.i_doublef(); 130 xx.i_floatf(); 131 xx.i_intf(); 132 xx.i_longf(); 133 xx.i_shortf(); 134 xx.i_booleanf(); 135 xx.i_stringf(); 136 xx.i_intArrayf(); 137 xx.i_objectArrayf(); 138 xx.i_classf(); 139 xx.i_classLoaderf(); 140 xx.i_threadf(); 141 xx.i_threadGroupf(); 142 xx.i_nullObjectf(); 143 xx.i_objectf(); 144 xx.i_voidf(); 145 146 } 147 148 public static void main(String[] args) throws Exception { 149 /* 150 * The debugger will stop at the start of main, 151 * set breakpoints and then do a resume. 152 */ 153 System.err.println("debugee in main"); 154 155 EarlyReturnNegativeTarg xx = 156 new EarlyReturnNegativeTarg(); 157 158 doit(xx); 159 } 160} 161 162 163 164public class EarlyReturnNegativeTest extends TestScaffold { 165 166 static VirtualMachineManager vmm ; 167 ClassType targetClass; 168 Field theValueField; 169 170 ByteValue byteVV; 171 CharValue charVV; 172 DoubleValue doubleVV; 173 FloatValue floatVV; 174 IntegerValue integerVV; 175 LongValue longVV; 176 ShortValue shortVV; 177 BooleanValue booleanVV; 178 ObjectReference objectVV; 179 ArrayReference intArrayVV; 180 ArrayReference objectArrayVV; 181 VoidValue voidVV; 182 183 EarlyReturnNegativeTest(String args[]) { 184 super(args); 185 } 186 187 public static void main(String[] args) throws Exception { 188 EarlyReturnNegativeTest meee = new EarlyReturnNegativeTest(args); 189 vmm = Bootstrap.virtualMachineManager(); 190 meee.startTests(); 191 } 192 193 public BreakpointRequest setBreakpoint(String clsName, 194 String methodName, 195 String methodSignature) { 196 ReferenceType rt = findReferenceType(clsName); 197 if (rt == null) { 198 rt = resumeToPrepareOf(clsName).referenceType(); 199 } 200 201 Method method = findMethod(rt, methodName, methodSignature); 202 if (method == null) { 203 throw new IllegalArgumentException("Bad method name/signature"); 204 } 205 BreakpointRequest bpr = eventRequestManager().createBreakpointRequest(method.location()); 206 bpr.setSuspendPolicy(EventRequest.SUSPEND_ALL); 207 bpr.enable(); 208 return bpr; 209 } 210 211 void doEarly(ThreadReference tr, String methodName, Value val) { 212 try { 213 tr.forceEarlyReturn(val); 214 } catch (InvalidTypeException ex) { 215 System.out.println("Ok: " + methodName); 216 return; 217 } catch (Exception ex) { 218 failure("failure: " + ex.toString()); 219 ex.printStackTrace(); 220 return; 221 } 222 failure("Expected InvalidTypeException for " + methodName + ", " + val + " but didn't get it."); 223 } 224 225 public void breakpointReached(BreakpointEvent event) { 226 String origMethodName = event.location().method().name(); 227 String methodName = origMethodName.substring(2); 228 ThreadReference tr = event.thread(); 229 230 if (vmm.majorInterfaceVersion() >= 1 && 231 vmm.minorInterfaceVersion() >= 6 && 232 vm().canForceEarlyReturn()) { 233 234 /* There are some incompatible classes of values. In the following, 235 * we test each combination. 236 */ 237 if ("shortf".equals(methodName)){ 238 doEarly(tr, origMethodName, booleanVV); 239 doEarly(tr, origMethodName, objectVV); 240 doEarly(tr, origMethodName, voidVV); 241 doEarly(tr, origMethodName, intArrayVV); 242 doEarly(tr, origMethodName, objectArrayVV); 243 244 } else if ("booleanf".equals(methodName)) { 245 doEarly(tr, origMethodName, shortVV); 246 doEarly(tr, origMethodName, objectVV); 247 doEarly(tr, origMethodName, voidVV); 248 doEarly(tr, origMethodName, intArrayVV); 249 doEarly(tr, origMethodName, objectArrayVV); 250 251 } else if ("intArrayf".equals(methodName)) { 252 doEarly(tr, origMethodName, booleanVV); 253 doEarly(tr, origMethodName, shortVV); 254 doEarly(tr, origMethodName, voidVV); 255 doEarly(tr, origMethodName, objectVV); 256 doEarly(tr, origMethodName, objectArrayVV); 257 258 } else if ("objectArrayf".equals(methodName)) { 259 doEarly(tr, origMethodName, booleanVV); 260 doEarly(tr, origMethodName, shortVV); 261 doEarly(tr, origMethodName, voidVV); 262 doEarly(tr, origMethodName, objectVV); 263 doEarly(tr, origMethodName, intArrayVV); 264 265 } else if ("objectf".equals(methodName)) { 266 doEarly(tr, origMethodName, booleanVV); 267 doEarly(tr, origMethodName, shortVV); 268 doEarly(tr, origMethodName, voidVV); 269 270 } else if ("voidf".equals(methodName)) { 271 doEarly(tr, origMethodName, booleanVV); 272 doEarly(tr, origMethodName, shortVV); 273 doEarly(tr, origMethodName, objectVV); 274 doEarly(tr, origMethodName, intArrayVV); 275 doEarly(tr, origMethodName, objectArrayVV); 276 277 } else { 278 // just ignore others 279 System.out.println("Ignoring: " + methodName); 280 return; 281 } 282 } else { 283 System.out.println("Cannot force early return for method: " + origMethodName); 284 } 285 } 286 287 protected void runTests() throws Exception { 288 /* 289 * Get to the top of main() 290 * to determine targetClass and mainThread 291 */ 292 293 BreakpointEvent bpe = startToMain("EarlyReturnNegativeTarg"); 294 targetClass = (ClassType)bpe.location().declaringType(); 295 mainThread = bpe.thread(); 296 297 /* 298 * We set and enable breakpoints on all of the interesting 299 * methods called by doit(). In the breakpointReached() 300 * handler we force an early return with a different return 301 * value. 302 * 303 */ 304 305 setBreakpoint("EarlyReturnNegativeTarg", "i_bytef", "()B"); 306 setBreakpoint("EarlyReturnNegativeTarg", "i_charf", "()C"); 307 setBreakpoint("EarlyReturnNegativeTarg", "i_doublef", "()D"); 308 setBreakpoint("EarlyReturnNegativeTarg", "i_floatf", "()F"); 309 setBreakpoint("EarlyReturnNegativeTarg", "i_intf", "()I"); 310 setBreakpoint("EarlyReturnNegativeTarg", "i_longf", "()J"); 311 setBreakpoint("EarlyReturnNegativeTarg", "i_shortf", "()S"); 312 setBreakpoint("EarlyReturnNegativeTarg", "i_booleanf", "()Z"); 313 setBreakpoint("EarlyReturnNegativeTarg", "i_stringf", "()Ljava/lang/String;"); 314 setBreakpoint("EarlyReturnNegativeTarg", "i_intArrayf", "()[I"); 315 setBreakpoint("EarlyReturnNegativeTarg", "i_objectArrayf", "()[Ljava/lang/Object;"); 316 setBreakpoint("EarlyReturnNegativeTarg", "i_classf", "()Ljava/lang/Class;"); 317 setBreakpoint("EarlyReturnNegativeTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;"); 318 setBreakpoint("EarlyReturnNegativeTarg", "i_threadf", "()Ljava/lang/Thread;"); 319 setBreakpoint("EarlyReturnNegativeTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;"); 320 setBreakpoint("EarlyReturnNegativeTarg", "i_nullObjectf", "()Ljava/lang/Object;"); 321 setBreakpoint("EarlyReturnNegativeTarg", "i_objectf", "()Ljava/lang/Object;"); 322 setBreakpoint("EarlyReturnNegativeTarg", "i_voidf", "()V"); 323 324 /* Create Value objects to be passed in forceEarlyReturn calls */ 325 Field theValueField = targetClass.fieldByName("byteValue"); 326 byteVV = (ByteValue)targetClass.getValue(theValueField); 327 328 theValueField = targetClass.fieldByName("charValue"); 329 charVV = (CharValue)targetClass.getValue(theValueField); 330 331 theValueField = targetClass.fieldByName("doubleValue"); 332 doubleVV = (DoubleValue)targetClass.getValue(theValueField); 333 334 theValueField = targetClass.fieldByName("floatValue"); 335 floatVV = (FloatValue)targetClass.getValue(theValueField); 336 337 theValueField = targetClass.fieldByName("intValue"); 338 integerVV = (IntegerValue)targetClass.getValue(theValueField); 339 340 theValueField = targetClass.fieldByName("longValue"); 341 longVV = (LongValue)targetClass.getValue(theValueField); 342 343 theValueField = targetClass.fieldByName("shortValue"); 344 shortVV = (ShortValue)targetClass.getValue(theValueField); 345 346 theValueField = targetClass.fieldByName("booleanValue"); 347 booleanVV = (BooleanValue)targetClass.getValue(theValueField); 348 349 theValueField = targetClass.fieldByName("objectValue"); 350 objectVV = (ObjectReference)targetClass.getValue(theValueField); 351 352 theValueField = targetClass.fieldByName("intArrayValue"); 353 intArrayVV = (ArrayReference)targetClass.getValue(theValueField); 354 355 theValueField = targetClass.fieldByName("objectArrayValue"); 356 objectArrayVV = (ArrayReference)targetClass.getValue(theValueField); 357 358 voidVV = vm().mirrorOfVoid(); 359 360 /* Here we go. This adds 'this' as a listener so 361 * that our handlers above will be called. 362 */ 363 listenUntilVMDisconnect(); 364 365 if (!testFailed) { 366 System.out.println(); 367 System.out.println("EarlyReturnNegativeTest: passed"); 368 } else { 369 System.out.println(); 370 System.out.println("EarlyReturnNegativeTest: failed"); 371 throw new Exception("EarlyReturnNegativeTest: failed"); 372 } 373 } 374} 375