1 /* 2 * Copyright (c) 2006, 2016, 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 */ 35 import com.sun.jdi.*; 36 import com.sun.jdi.event.*; 37 import com.sun.jdi.request.*; 38 import java.util.*; 39 import java.net.URLClassLoader; 40 import java.net.URL; 41 import 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 62 class 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 164 public 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 (vm().canForceEarlyReturn()) { 231 232 /* There are some incompatible classes of values. In the following, 233 * we test each combination. 234 */ 235 if ("shortf".equals(methodName)){ 236 doEarly(tr, origMethodName, booleanVV); 237 doEarly(tr, origMethodName, objectVV); 238 doEarly(tr, origMethodName, voidVV); 239 doEarly(tr, origMethodName, intArrayVV); 240 doEarly(tr, origMethodName, objectArrayVV); 241 242 } else if ("booleanf".equals(methodName)) { 243 doEarly(tr, origMethodName, shortVV); 244 doEarly(tr, origMethodName, objectVV); 245 doEarly(tr, origMethodName, voidVV); 246 doEarly(tr, origMethodName, intArrayVV); 247 doEarly(tr, origMethodName, objectArrayVV); 248 249 } else if ("intArrayf".equals(methodName)) { 250 doEarly(tr, origMethodName, booleanVV); 251 doEarly(tr, origMethodName, shortVV); 252 doEarly(tr, origMethodName, voidVV); 253 doEarly(tr, origMethodName, objectVV); 254 doEarly(tr, origMethodName, objectArrayVV); 255 256 } else if ("objectArrayf".equals(methodName)) { 257 doEarly(tr, origMethodName, booleanVV); 258 doEarly(tr, origMethodName, shortVV); 259 doEarly(tr, origMethodName, voidVV); 260 doEarly(tr, origMethodName, objectVV); 261 doEarly(tr, origMethodName, intArrayVV); 262 263 } else if ("objectf".equals(methodName)) { 264 doEarly(tr, origMethodName, booleanVV); 265 doEarly(tr, origMethodName, shortVV); 266 doEarly(tr, origMethodName, voidVV); 267 268 } else if ("voidf".equals(methodName)) { 269 doEarly(tr, origMethodName, booleanVV); 270 doEarly(tr, origMethodName, shortVV); 271 doEarly(tr, origMethodName, objectVV); 272 doEarly(tr, origMethodName, intArrayVV); 273 doEarly(tr, origMethodName, objectArrayVV); 274 275 } else { 276 // just ignore others 277 System.out.println("Ignoring: " + methodName); 278 return; 279 } 280 } else { 281 System.out.println("Cannot force early return for method: " + origMethodName); 282 } 283 } 284 285 protected void runTests() throws Exception { 286 /* 287 * Get to the top of main() 288 * to determine targetClass and mainThread 289 */ 290 291 BreakpointEvent bpe = startToMain("EarlyReturnNegativeTarg"); 292 targetClass = (ClassType)bpe.location().declaringType(); 293 mainThread = bpe.thread(); 294 295 /* 296 * We set and enable breakpoints on all of the interesting 297 * methods called by doit(). In the breakpointReached() 298 * handler we force an early return with a different return 299 * value. 300 * 301 */ 302 303 setBreakpoint("EarlyReturnNegativeTarg", "i_bytef", "()B"); 304 setBreakpoint("EarlyReturnNegativeTarg", "i_charf", "()C"); 305 setBreakpoint("EarlyReturnNegativeTarg", "i_doublef", "()D"); 306 setBreakpoint("EarlyReturnNegativeTarg", "i_floatf", "()F"); 307 setBreakpoint("EarlyReturnNegativeTarg", "i_intf", "()I"); 308 setBreakpoint("EarlyReturnNegativeTarg", "i_longf", "()J"); 309 setBreakpoint("EarlyReturnNegativeTarg", "i_shortf", "()S"); 310 setBreakpoint("EarlyReturnNegativeTarg", "i_booleanf", "()Z"); 311 setBreakpoint("EarlyReturnNegativeTarg", "i_stringf", "()Ljava/lang/String;"); 312 setBreakpoint("EarlyReturnNegativeTarg", "i_intArrayf", "()[I"); 313 setBreakpoint("EarlyReturnNegativeTarg", "i_objectArrayf", "()[Ljava/lang/Object;"); 314 setBreakpoint("EarlyReturnNegativeTarg", "i_classf", "()Ljava/lang/Class;"); 315 setBreakpoint("EarlyReturnNegativeTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;"); 316 setBreakpoint("EarlyReturnNegativeTarg", "i_threadf", "()Ljava/lang/Thread;"); 317 setBreakpoint("EarlyReturnNegativeTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;"); 318 setBreakpoint("EarlyReturnNegativeTarg", "i_nullObjectf", "()Ljava/lang/Object;"); 319 setBreakpoint("EarlyReturnNegativeTarg", "i_objectf", "()Ljava/lang/Object;"); 320 setBreakpoint("EarlyReturnNegativeTarg", "i_voidf", "()V"); 321 322 /* Create Value objects to be passed in forceEarlyReturn calls */ 323 Field theValueField = targetClass.fieldByName("byteValue"); 324 byteVV = (ByteValue)targetClass.getValue(theValueField); 325 326 theValueField = targetClass.fieldByName("charValue"); 327 charVV = (CharValue)targetClass.getValue(theValueField); 328 329 theValueField = targetClass.fieldByName("doubleValue"); 330 doubleVV = (DoubleValue)targetClass.getValue(theValueField); 331 332 theValueField = targetClass.fieldByName("floatValue"); 333 floatVV = (FloatValue)targetClass.getValue(theValueField); 334 335 theValueField = targetClass.fieldByName("intValue"); 336 integerVV = (IntegerValue)targetClass.getValue(theValueField); 337 338 theValueField = targetClass.fieldByName("longValue"); 339 longVV = (LongValue)targetClass.getValue(theValueField); 340 341 theValueField = targetClass.fieldByName("shortValue"); 342 shortVV = (ShortValue)targetClass.getValue(theValueField); 343 344 theValueField = targetClass.fieldByName("booleanValue"); 345 booleanVV = (BooleanValue)targetClass.getValue(theValueField); 346 347 theValueField = targetClass.fieldByName("objectValue"); 348 objectVV = (ObjectReference)targetClass.getValue(theValueField); 349 350 theValueField = targetClass.fieldByName("intArrayValue"); 351 intArrayVV = (ArrayReference)targetClass.getValue(theValueField); 352 353 theValueField = targetClass.fieldByName("objectArrayValue"); 354 objectArrayVV = (ArrayReference)targetClass.getValue(theValueField); 355 356 voidVV = vm().mirrorOfVoid(); 357 358 /* Here we go. This adds 'this' as a listener so 359 * that our handlers above will be called. 360 */ 361 listenUntilVMDisconnect(); 362 363 if (!testFailed) { 364 System.out.println(); 365 System.out.println("EarlyReturnNegativeTest: passed"); 366 } else { 367 System.out.println(); 368 System.out.println("EarlyReturnNegativeTest: failed"); 369 throw new Exception("EarlyReturnNegativeTest: failed"); 370 } 371 } 372 }