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 */
34import com.sun.jdi.*;
35import com.sun.jdi.event.*;
36import com.sun.jdi.request.*;
37import java.util.*;
38import java.net.URLClassLoader;
39import java.net.URL;
40import 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
61class 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
163public 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}
372