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 }