child_process: add safety checks on stdio access
authorcjihrig <cjihrig@gmail.com>
Thu, 12 Nov 2015 19:30:20 +0000 (14:30 -0500)
committerJames M Snell <jasnell@gmail.com>
Wed, 23 Dec 2015 16:38:33 +0000 (08:38 -0800)
When a child process is spawned, there is no guarantee that stdout
and stderr will be created successfully. This commit adds checks
before attempting to access the streams.

PR-URL: https://github.com/nodejs/node/pull/3799
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
lib/child_process.js

index 151fb51..ddbb044 100644 (file)
@@ -222,14 +222,22 @@ exports.execFile = function(file /*, args, options, callback*/) {
 
   function errorhandler(e) {
     ex = e;
-    child.stdout.destroy();
-    child.stderr.destroy();
+
+    if (child.stdout)
+      child.stdout.destroy();
+
+    if (child.stderr)
+      child.stderr.destroy();
+
     exithandler();
   }
 
   function kill() {
-    child.stdout.destroy();
-    child.stderr.destroy();
+    if (child.stdout)
+      child.stdout.destroy();
+
+    if (child.stderr)
+      child.stderr.destroy();
 
     killed = true;
     try {
@@ -247,37 +255,42 @@ exports.execFile = function(file /*, args, options, callback*/) {
     }, options.timeout);
   }
 
-  child.stdout.addListener('data', function(chunk) {
-    stdoutLen += chunk.length;
-
-    if (stdoutLen > options.maxBuffer) {
-      ex = new Error('stdout maxBuffer exceeded.');
-      kill();
-    } else {
-      if (!encoding)
-        _stdout.push(chunk);
-      else
-        _stdout += chunk;
-    }
-  });
-
-  child.stderr.addListener('data', function(chunk) {
-    stderrLen += chunk.length;
-
-    if (stderrLen > options.maxBuffer) {
-      ex = new Error('stderr maxBuffer exceeded.');
-      kill();
-    } else {
-      if (!encoding)
-        _stderr.push(chunk);
-      else
-        _stderr += chunk;
-    }
-  });
+  if (child.stdout) {
+    if (encoding)
+      child.stdout.setEncoding(encoding);
+
+    child.stdout.addListener('data', function(chunk) {
+      stdoutLen += chunk.length;
+
+      if (stdoutLen > options.maxBuffer) {
+        ex = new Error('stdout maxBuffer exceeded');
+        kill();
+      } else {
+        if (!encoding)
+          _stdout.push(chunk);
+        else
+          _stdout += chunk;
+      }
+    });
+  }
 
-  if (encoding) {
-    child.stderr.setEncoding(encoding);
-    child.stdout.setEncoding(encoding);
+  if (child.stderr) {
+    if (encoding)
+      child.stderr.setEncoding(encoding);
+
+    child.stderr.addListener('data', function(chunk) {
+      stderrLen += chunk.length;
+
+      if (stderrLen > options.maxBuffer) {
+        ex = new Error('stderr maxBuffer exceeded');
+        kill();
+      } else {
+        if (!encoding)
+          _stderr.push(chunk);
+        else
+          _stderr += chunk;
+      }
+    });
   }
 
   child.addListener('close', exithandler);