8015911: $EXEC does not handle large outputs
Reviewed-by: sundar, attila
Contributed-by: james.laskey@oracle.com
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Jun 05 12:44:24 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Jun 05 10:32:50 2013 -0300
@@ -32,9 +32,8 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Map;
@@ -165,36 +164,61 @@
// Start the process.
final Process process = processBuilder.start();
+ final IOException exception[] = new IOException[2];
+
+ // Collect output.
+ final StringBuilder outBuffer = new StringBuilder();
+ Thread outThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ char buffer[] = new char[1024];
+ try (final InputStreamReader inputStream = new InputStreamReader(process.getInputStream())) {
+ for (int length; (length = inputStream.read(buffer, 0, buffer.length)) != -1; ) {
+ outBuffer.append(buffer, 0, length);
+ }
+ } catch (IOException ex) {
+ exception[0] = ex;
+ }
+ }
+ }, "$EXEC output");
+
+ // Collect errors.
+ final StringBuilder errBuffer = new StringBuilder();
+ Thread errThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ char buffer[] = new char[1024];
+ try (final InputStreamReader inputStream = new InputStreamReader(process.getErrorStream())) {
+ for (int length; (length = inputStream.read(buffer, 0, buffer.length)) != -1; ) {
+ outBuffer.append(buffer, 0, length);
+ }
+ } catch (IOException ex) {
+ exception[1] = ex;
+ }
+ }
+ }, "$EXEC error");
+
+ // Start gathering output.
+ outThread.start();
+ errThread.start();
// If input is present, pass on to process.
- try (OutputStream outputStream = process.getOutputStream()) {
+ try (OutputStreamWriter outputStream = new OutputStreamWriter(process.getOutputStream())) {
if (input != UNDEFINED) {
- outputStream.write(JSType.toString(input).getBytes());
+ String in = JSType.toString(input);
+ outputStream.write(in, 0, in.length());
}
+ } catch (IOException ex) {
+ // Process was not expecting input. May be normal state of affairs.
}
// Wait for the process to complete.
final int exit = process.waitFor();
+ outThread.join();
+ errThread.join();
- // Collect output.
- String out;
- try (InputStream inputStream = process.getInputStream()) {
- final StringBuilder outBuffer = new StringBuilder();
- for (int ch; (ch = inputStream.read()) != -1; ) {
- outBuffer.append((char)ch);
- }
- out = outBuffer.toString();
- }
-
- // Collect errors.
- String err;
- try (InputStream errorStream = process.getErrorStream()) {
- final StringBuilder errBuffer = new StringBuilder();
- for (int ch; (ch = errorStream.read()) != -1; ) {
- errBuffer.append((char)ch);
- }
- err = errBuffer.toString();
- }
+ final String out = outBuffer.toString();
+ final String err = errBuffer.toString();
// Set globals for secondary results.
final boolean isStrict = global.isStrictContext();
@@ -202,6 +226,13 @@
global.set(ERR_NAME, err, isStrict);
global.set(EXIT_NAME, exit, isStrict);
+ // Propagate exception if present.
+ for (int i = 0; i < exception.length; i++) {
+ if (exception[i] != null) {
+ throw exception[i];
+ }
+ }
+
// Return the result from stdout.
return out;
}