Skip to content

8318736: com/sun/jdi/JdwpOnThrowTest.java failed with "transport error 202: bind failed: Address already in use" #1949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions test/jdk/com/sun/jdi/JdwpOnThrowTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ public class JdwpOnThrowTest {
private static AttachingConnector attachingConnector;

public static void main(String[] args) throws Exception {
int port = findFreePort();
try (Debuggee debuggee = Debuggee.launcher("ThrowCaughtException").setAddress("localhost:" + port)
.enableOnThrow("Ex", "Start").setSuspended(true).launch()) {
try (Debuggee debuggee = Debuggee.launcher("ThrowCaughtException")
.enableOnThrow("Ex").setSuspended(true).launch()) {
VirtualMachine vm = null;
try {
vm = attach("localhost", "" + port);
vm = attach("localhost", debuggee.getAddress());
EventQueue queue = vm.eventQueue();
log("Waiting for exception event");
long start = System.currentTimeMillis();
Expand Down Expand Up @@ -110,14 +109,6 @@ private static void verifyExceptionEvent(ExceptionEvent ex) throws Exception {
}
}

private static int findFreePort() {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static VirtualMachine attach(String address, String port) throws IOException {
if (attachingConnector == null) {
attachingConnector = (AttachingConnector)getConnector(ATTACH_CONNECTOR);
Expand Down
79 changes: 46 additions & 33 deletions test/jdk/com/sun/jdi/lib/jdb/Debuggee.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package lib.jdb;

import jdk.test.lib.Utils;
import jdk.test.lib.util.Pair;
import jdk.test.lib.process.ProcessTools;

import java.io.Closeable;
Expand All @@ -32,6 +33,7 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -70,8 +72,7 @@ public static class Launcher {
private String address = null;
private boolean suspended = true;
private String onthrow = "";
private boolean waitForPortPrint = true;
private String expectedOutputBeforeThrow = "";
private static final String LAUNCH_ECHO_STRING = "Listen Args:";

private Launcher(String mainClass) {
this.mainClass = mainClass;
Expand Down Expand Up @@ -104,11 +105,8 @@ public Launcher setSuspended(boolean value) {
return this;
}

// required to pass non null port with address and emit string before the throw
public Launcher enableOnThrow(String value, String expectedOutputBeforeThrow) {
this.onthrow = value;
this.waitForPortPrint = false;
this.expectedOutputBeforeThrow = expectedOutputBeforeThrow;
public Launcher enableOnThrow(String exceptionClassName) {
this.onthrow = exceptionClassName;
return this;
}

Expand All @@ -117,7 +115,7 @@ public ProcessBuilder prepare() {
if (vmOptions != null) {
debuggeeArgs.add(vmOptions);
}
String onthrowArgs = onthrow.isEmpty() ? "" : ",onthrow=" + onthrow + ",launch=exit";
String onthrowArgs = onthrow.isEmpty() ? "" : ",onthrow=" + onthrow + ",launch=echo " + LAUNCH_ECHO_STRING;
debuggeeArgs.add("-agentlib:jdwp=transport=" + transport
+ (address == null ? "" : ",address=" + address)
+ ",server=y,suspend=" + (suspended ? "y" : "n")
Expand All @@ -128,41 +126,57 @@ public ProcessBuilder prepare() {
}

public Debuggee launch(String name) {
return new Debuggee(prepare(), name, waitForPortPrint, expectedOutputBeforeThrow);
return new Debuggee(prepare(), name,
onthrow.isEmpty() ?
Launcher::parseListenAddress :
Launcher::parseLaunchEchoListenAddress
);
}
public Debuggee launch() {
return launch("debuggee");
}
}

// starts the process, waits for "Listening for transport" output and detects transport/address
private Debuggee(ProcessBuilder pb, String name, boolean waitForPortPrint, String expectedOutputBeforeThrow) {
// debuggeeListen[0] - transport, debuggeeListen[1] - address
String[] debuggeeListen = new String[2];
Pattern listenRegexp = Pattern.compile("Listening for transport \\b(.+)\\b at address: \\b(.+)\\b");
if (!waitForPortPrint) {
try {
p = ProcessTools.startProcess(name, pb, s -> {output.add(s);}, s -> {
return s.equals(expectedOutputBeforeThrow);
}, 30, TimeUnit.SECONDS);
} catch (IOException | InterruptedException | TimeoutException ex) {
throw new RuntimeException("failed to launch debuggee", ex);
/**
* Parses debuggee output to get listening transport and address, printed by `launch=echo`.
* Returns null if the string specified does not contain required info.
*/
private static Pair<String, String> parseLaunchEchoListenAddress(String debuggeeOutput) {
Pattern listenRegexp = Pattern.compile(LAUNCH_ECHO_STRING + " \\b(.+)\\b \\b(.+)\\b");
Matcher m = listenRegexp.matcher(debuggeeOutput);
if (m.find()) {
return new Pair<String, String>(m.group(1), m.group(2));
}
transport = null;
address = null;
return;
return null;
}

/**
* Parses debuggee output to get listening transport and address, printed by `launch=echo`.
* Returns null if the string specified does not contain required info.
*/
private static Pair<String, String> parseListenAddress(String debuggeeOutput) {
Pattern listenRegexp = Pattern.compile("Listening for transport \\b(.+)\\b at address: \\b(.+)\\b");
Matcher m = listenRegexp.matcher(debuggeeOutput);
if (m.find()) {
return new Pair<String, String>(m.group(1), m.group(2));
}
return null;
}
}

// starts the process, waits until the provided addressDetector detects transport/address from the process output
private Debuggee(ProcessBuilder pb, String name, Function<String, Pair<String, String>> addressDetector) {
String[] debuggeeListen = new String[2];
try {
p = ProcessTools.startProcess(name, pb,
s -> output.add(s), // output consumer
s -> { // warm-up predicate
Matcher m = listenRegexp.matcher(s);
if (!m.matches()) {
return false;
s -> {
Pair<String, String> addr = addressDetector.apply(s);
if (addr != null) {
debuggeeListen[0] = addr.first;
debuggeeListen[1] = addr.second;
return true;
}
debuggeeListen[0] = m.group(1);
debuggeeListen[1] = m.group(2);
return true;
return false;
},
30, TimeUnit.SECONDS);
transport = debuggeeListen[0];
Expand Down Expand Up @@ -219,5 +233,4 @@ public void close() throws IOException {
p.destroy();
}
}

}