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 }