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("file:/foo");
81         } catch (java.net.MalformedURLException ex) {
82             throw new AssertionError(ex);
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
s_show(String p1)99     public static String s_show(String p1) { return p1;}
100 
101     // These are the instance methods
i_bytef()102     public byte i_bytef()            { return byteValue; }
i_charf()103     public char i_charf()            { return charValue; }
i_doublef()104     public double i_doublef()        { return doubleValue; }
i_floatf()105     public float i_floatf()          { return floatValue; }
i_intf()106     public int i_intf()              { return intValue; }
i_longf()107     public long i_longf()            { return longValue; }
i_shortf()108     public short i_shortf()          { return shortValue; }
i_booleanf()109     public boolean i_booleanf()      { return booleanValue; }
i_stringf()110     public String i_stringf()        { return stringValue; }
i_classf()111     public Class i_classf()          { return classValue; }
i_classLoaderf()112     public ClassLoader i_classLoaderf()
113                                      { return classLoaderValue; }
i_threadf()114     public Thread i_threadf()        { return threadValue; }
i_threadGroupf()115     public ThreadGroup i_threadGroupf()
116                                      { return threadGroupValue; }
i_intArrayf()117     public int[] i_intArrayf()       { return intArrayValue; }
i_objectArrayf()118     public Object[] i_objectArrayf() { return objectArrayValue; }
i_nullObjectf()119     public Object i_nullObjectf()    { return null; }
i_objectf()120     public Object i_objectf()        { return objectValue; }
i_voidf()121     public void i_voidf()            {}
122 
doit(EarlyReturnNegativeTarg xx)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 
main(String[] args)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 
EarlyReturnNegativeTest(String args[])183     EarlyReturnNegativeTest(String args[]) {
184         super(args);
185     }
186 
main(String[] args)187     public static void main(String[] args)      throws Exception {
188         EarlyReturnNegativeTest meee = new EarlyReturnNegativeTest(args);
189         vmm = Bootstrap.virtualMachineManager();
190         meee.startTests();
191     }
192 
setBreakpoint(String clsName, String methodName, String methodSignature)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 
doEarly(ThreadReference tr, String methodName, Value val)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 
breakpointReached(BreakpointEvent event)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 
runTests()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 }
373