8227868: jinfo and jstack can fail converting UTF8 output to strings

Reviewed-by: sgehwolf, dholmes, cjplummer
This commit is contained in:
Ralf Schmelter 2019-07-22 14:40:00 +02:00
parent 5732fe95a6
commit 678b5df6c7
6 changed files with 141 additions and 48 deletions

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.common;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Arrays;
/**
* A helper class which prints the content of input streams to print streams.
*/
public class PrintStreamPrinter {
/**
* Reads characters in UTF-8 format from the input stream and prints them
* with the given print stream. Closes the input stream before it returns.
*
* @return The number of printed characters.
*/
public static long drainUTF8(InputStream is, PrintStream ps) throws IOException {
long result = 0;
try (BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis, "UTF-8")) {
char c[] = new char[256];
int n;
do {
n = isr.read(c);
if (n > 0) {
result += n;
ps.print(n == c.length ? c : Arrays.copyOf(c, n));
}
} while (n > 0);
}
return result;
}
}

View File

@ -25,13 +25,10 @@
package sun.tools.jcmd;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.net.URISyntaxException;
@ -42,6 +39,7 @@ import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
import sun.tools.common.PrintStreamPrinter;
import sun.tools.jstat.JStatLogger;
import sun.jvmstat.monitor.Monitor;
import sun.jvmstat.monitor.MonitoredHost;
@ -122,23 +120,11 @@ public class JCmd {
if (line.trim().equals("stop")) {
break;
}
try (InputStream in = hvm.executeJCmd(line);
InputStreamReader isr = new InputStreamReader(in, "UTF-8")) {
// read to EOF and just print output
char c[] = new char[256];
int n;
boolean messagePrinted = false;
do {
n = isr.read(c);
if (n > 0) {
String s = new String(c, 0, n);
System.out.print(s);
messagePrinted = true;
}
} while (n > 0);
if (!messagePrinted) {
System.out.println("Command executed successfully");
}
InputStream is = hvm.executeJCmd(line);
if (PrintStreamPrinter.drainUTF8(is, System.out) == 0) {
System.out.println("Command executed successfully");
}
}
vm.detach();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,10 +30,10 @@ import java.io.InputStream;
import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
import sun.tools.common.PrintStreamPrinter;
/*
* This class is the main class for the JInfo utility. It parses its arguments
@ -203,17 +203,7 @@ final public class JInfo {
// Read the stream from the target VM until EOF, then detach
private static void drain(VirtualMachine vm, InputStream in) throws IOException {
// read to EOF and just print output
byte b[] = new byte[256];
int n;
do {
n = in.read(b);
if (n > 0) {
String s = new String(b, 0, n, "UTF-8");
System.out.print(s);
}
} while (n > 0);
in.close();
PrintStreamPrinter.drainUTF8(in, System.out);
vm.detach();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,9 +29,9 @@ import java.io.InputStream;
import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
import sun.tools.common.PrintStreamPrinter;
/*
* This class is the main class for the JStack utility. It parses its arguments
@ -128,18 +128,8 @@ public class JStack {
// Cast to HotSpotVirtualMachine as this is implementation specific
// method.
InputStream in = ((HotSpotVirtualMachine)vm).remoteDataDump((Object[])args);
// read to EOF and just print output
byte b[] = new byte[256];
int n;
do {
n = in.read(b);
if (n > 0) {
String s = new String(b, 0, n, "UTF-8");
System.out.print(s);
}
} while (n > 0);
in.close();
PrintStreamPrinter.drainUTF8(in, System.out);
vm.detach();
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.JDKToolLauncher;
/*
* @test
* @bug 8222491
* @summary Tests if we handle the encoding of jcmd output correctly.
* @library /test/lib
* @run main JcmdOutputEncodingTest
*/
public class JcmdOutputEncodingTest {
public static void main(String[] args) throws Exception {
testThreadDump();
}
private static void testThreadDump() throws Exception {
String markerName = "markerName" + "\u00e4\u0bb5".repeat(10_000);
Thread.currentThread().setName(markerName);
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jcmd");
launcher.addToolArg(Long.toString(ProcessTools.getProcessId()));
launcher.addToolArg("Thread.print");
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(launcher.getCommand());
OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
output.shouldHaveExitValue(0);
output.shouldContain(markerName);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@ import jdk.test.lib.JDKToolLauncher;
public class BasicJStackTest {
private static ProcessBuilder processBuilder = new ProcessBuilder();
private static String markerName = "markerName" + "\u00e4\u0bb5".repeat(10_000);
public static void main(String[] args) throws Exception {
testJstackNoArgs();
@ -45,14 +46,17 @@ public class BasicJStackTest {
private static void testJstackNoArgs() throws Exception {
OutputAnalyzer output = jstack();
output.shouldHaveExitValue(0);
output.shouldContain(markerName);
}
private static void testJstack_l() throws Exception {
OutputAnalyzer output = jstack("-l");
output.shouldHaveExitValue(0);
output.shouldContain(markerName);
}
private static OutputAnalyzer jstack(String... toolArgs) throws Exception {
Thread.currentThread().setName(markerName);
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstack");
launcher.addVMArg("-XX:+UsePerfData");
if (toolArgs != null) {