1 /*
   2  * Copyright (c) 2008, 2015, 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 6700889
  27  *  @summary  Thread resume invalidates all stack frames, even from other threads
  28  *
  29  *  @author jjh
  30  *
  31  *  @modules jdk.jdi
  32  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  *  @run compile -g ResumeOneThreadTest.java
  34  *  @run driver ResumeOneThreadTest
  35  */
  36 import com.sun.jdi.*;
  37 import com.sun.jdi.event.*;
  38 import com.sun.jdi.request.*;
  39 
  40 import java.util.*;
  41 
  42 class ResumeOneThreadTarg extends Thread {
  43     static String name1 = "Thread 1";
  44     static String name2 = "Thread 2";
  45 
  46     public ResumeOneThreadTarg(String name) {
  47         super(name);
  48     }
  49 
  50     public static void main(String[] args) {
  51         System.out.println("    Debuggee: Howdy!");
  52         ResumeOneThreadTarg t1 = new ResumeOneThreadTarg(name1);
  53         ResumeOneThreadTarg t2 = new ResumeOneThreadTarg(name2);
  54 
  55         t1.start();
  56         t2.start();
  57     }
  58 
  59     // This just starts two threads. Each runs to a bkpt.
  60     public void run() {
  61         if (getName().equals(name1)) {
  62             run1();
  63         } else {
  64             run2();
  65         }
  66     }
  67 
  68     public void bkpt1(String p1) {
  69         System.out.println("    Debuggee: bkpt 1");
  70     }
  71 
  72     public void run1() {
  73         bkpt1("Hello Alviso!");
  74     }
  75 
  76 
  77 
  78     public void bkpt2() {
  79         System.out.println("    Debuggee: bkpt 2");
  80     }
  81 
  82     public void run2() {
  83         bkpt2();
  84     }
  85 }
  86 
  87 /********** test program **********/
  88 
  89 public class ResumeOneThreadTest extends TestScaffold {
  90     ReferenceType targetClass;
  91     ThreadReference mainThread;
  92 
  93     BreakpointRequest request1;
  94     BreakpointRequest request2;
  95 
  96     ThreadReference thread1 = null;
  97     ThreadReference thread2 = null;;
  98     boolean theVMisDead = false;
  99 
 100     ResumeOneThreadTest (String args[]) {
 101         super(args);
 102     }
 103 
 104     public static void main(String[] args)      throws Exception {
 105         new ResumeOneThreadTest(args).startTests();
 106     }
 107 
 108 
 109     synchronized public void breakpointReached(BreakpointEvent event) {
 110         println("-- Got bkpt at: " + event.location());
 111         ThreadReference eventThread = event.thread();
 112 
 113         if (eventThread.name().equals(ResumeOneThreadTarg.name1)) {
 114             thread1 = eventThread;
 115         }
 116 
 117         if (eventThread.name().equals(ResumeOneThreadTarg.name2)) {
 118             thread2 = eventThread;
 119         }
 120     }
 121 
 122     public void vmDied(VMDeathEvent event) {
 123         theVMisDead = true;
 124     }
 125 
 126     synchronized public void eventSetComplete(EventSet set) {
 127         if (theVMisDead) {
 128             return;
 129         }
 130         if (thread1 == null || thread2 == null) {
 131             // Don't do a set.resume(), just let the other thread
 132             // keep running until it hits its bkpt.
 133             return;
 134         }
 135 
 136         // Both threads are stopped at their bkpts.  Get a StackFrame from
 137         // Thread 1 then resume Thread 2 and verify that the saved StackFrame is
 138         // still valid.
 139 
 140         // suspend everything.
 141         println("-- All threads suspended");
 142         vm().suspend();
 143 
 144         StackFrame t1sf0 = null;
 145         try {
 146             t1sf0 = thread1.frame(0);
 147         } catch (IncompatibleThreadStateException ee) {
 148             failure("FAILED: Exception: " + ee);
 149         }
 150 
 151         println("-- t1sf0 args: " + t1sf0.getArgumentValues());
 152 
 153         // Ok, we have a StackFrame for thread 1.  Resume just thread 2
 154         // Note that thread 2 has been suspended twice - by the SUSPEND_ALL
 155         // bkpt, and by the above vm().suspend(), so we have to resume
 156         // it twice.
 157         request2.disable();
 158 
 159         thread2.resume();
 160         thread2.resume();
 161         println("-- Did Resume on thread 2");
 162 
 163         // Can we get frames for thread1?
 164         try {
 165             StackFrame t1sf0_1 = thread1.frame(0);
 166             if (!t1sf0.equals(t1sf0_1)) {
 167                 failure("FAILED: Got a different frame 0 for thread 1 after resuming thread 2");
 168             }
 169         } catch (IncompatibleThreadStateException ee) {
 170             failure("FAILED: Could not get frames for thread 1: Exception: " + ee);
 171         } catch (Exception ee) {
 172             failure("FAILED: Could not get frames for thread 1: Exception: " + ee);
 173         }
 174 
 175 
 176         try {
 177             println("-- t1sf0 args: " + t1sf0.getArgumentValues());
 178         } catch (InvalidStackFrameException ee) {
 179             // This is the failure.
 180             failure("FAILED Got InvalidStackFrameException");
 181             vm().dispose();
 182             throw(ee);
 183         }
 184 
 185         // Let the debuggee finish
 186         request1.disable();
 187         thread1.resume();
 188         vm().resume();
 189         println("--------------");
 190     }
 191 
 192     /********** test core **********/
 193 
 194     protected void runTests() throws Exception {
 195 
 196         /*
 197          * Get to the top of main()
 198          * to determine targetClass and mainThread
 199          */
 200         BreakpointEvent bpe = startToMain("ResumeOneThreadTarg");
 201         targetClass = bpe.location().declaringType();
 202         mainThread = bpe.thread();
 203         EventRequestManager erm = vm().eventRequestManager();
 204         final Thread mainThread = Thread.currentThread();
 205 
 206         /*
 207          * Set event requests
 208          */
 209 
 210         Location loc1 = findMethod(targetClass, "bkpt1", "(Ljava/lang/String;)V").location();
 211         request1 = erm.createBreakpointRequest(loc1);
 212         request1.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
 213         request1.enable();
 214 
 215         Location loc2 = findMethod(targetClass, "bkpt2", "()V").location();
 216         request2 = erm.createBreakpointRequest(loc2);
 217         request2.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
 218         request2.enable();
 219 
 220         /*
 221          * resume the target, listening for events
 222          */
 223         listenUntilVMDisconnect();
 224         /*
 225          * deal with results of test
 226          * if anything has called failure("foo") testFailed will be true
 227          */
 228         if (!testFailed) {
 229             println("ResumeOneThreadTest: passed");
 230         } else {
 231             throw new Exception("ResumeOneThreadTest: failed");
 232         }
 233     }
 234 }