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