From 9cd14d360302f45b4815cda0a5bf80c97db989cd Mon Sep 17 00:00:00 2001 From: Dean Brettle Date: Wed, 4 Jul 2018 22:09:27 -0700 Subject: [PATCH] :fix: bad handling of newlines in env vars Fix #17627 by using awk to portably separate env vars with \0 instead of \n. --- spec/update-process-env-spec.js | 18 ++++++------------ src/update-process-env.js | 10 +++++++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index f7948d998..2cddd6e46 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -220,17 +220,14 @@ describe('updateProcessEnv(launchEnv)', function () { process.platform = 'darwin' process.env.SHELL = '/my/custom/bash' - spawn.setDefault(spawn.simple(0, dedent` - FOO=BAR=BAZ=QUUX - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - `)) + spawn.setDefault(spawn.simple(0, 'FOO=BAR=BAZ=QUUX\0MULTILINE\nNAME=multiline\nvalue\0TERM=xterm-something\0PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path')) await updateProcessEnv(process.env) expect(spawn.calls.length).toBe(1) expect(spawn.calls[0].command).toBe('/my/custom/bash') - expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']) + expect(spawn.calls[0].args).toEqual(['-ilc', 'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s\\0",v,ENVIRON[v])}\'']) expect(process.env).toEqual({ FOO: 'BAR=BAZ=QUUX', + 'MULTILINE\nNAME': 'multiline\nvalue', TERM: 'xterm-something', PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path' }) @@ -246,17 +243,14 @@ describe('updateProcessEnv(launchEnv)', function () { process.platform = 'linux' process.env.SHELL = '/my/custom/bash' - spawn.setDefault(spawn.simple(0, dedent` - FOO=BAR=BAZ=QUUX - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - `)) + spawn.setDefault(spawn.simple(0, 'FOO=BAR=BAZ=QUUX\0MULTILINE\nNAME=multiline\nvalue\0TERM=xterm-something\0PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path')) await updateProcessEnv(process.env) expect(spawn.calls.length).toBe(1) expect(spawn.calls[0].command).toBe('/my/custom/bash') - expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']) + expect(spawn.calls[0].args).toEqual(['-ilc', 'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s\\0",v,ENVIRON[v])}\'']) expect(process.env).toEqual({ FOO: 'BAR=BAZ=QUUX', + 'MULTILINE\nNAME': 'multiline\nvalue', TERM: 'xterm-something', PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path' }) diff --git a/src/update-process-env.js b/src/update-process-env.js index 20d937d96..1d9ace5e7 100644 --- a/src/update-process-env.js +++ b/src/update-process-env.js @@ -13,6 +13,10 @@ const PLATFORMS_KNOWN_TO_WORK = new Set([ 'linux' ]) +// Shell command that returns env var=value lines separated by \0s so that +// newlines are handled properly +const ENV_COMMAND = 'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s\\0",v,ENVIRON[v])}\'' + async function updateProcessEnv (launchEnv) { let envToAssign if (launchEnv) { @@ -74,7 +78,7 @@ async function getEnvFromShell (env) { setTimeout(() => { cleanup() }, 5000) - child = childProcess.spawn(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8', detached: true, stdio: ['ignore', 'pipe', process.stderr]}) + child = childProcess.spawn(env.SHELL, ['-ilc', ENV_COMMAND], {encoding: 'utf8', detached: true, stdio: ['ignore', 'pipe', process.stderr]}) const buffers = [] child.on('error', (e) => { done = true @@ -98,7 +102,7 @@ async function getEnvFromShell (env) { if (error.handle) { error.handle() } - console.log('warning: ' + env.SHELL + ' -ilc "command env" failed with signal (' + error.signal + ')') + console.log('warning: ' + env.SHELL + ' -ilc "' + ENV_COMMAND + '" failed with signal (' + error.signal + ')') console.log(error) } @@ -107,7 +111,7 @@ async function getEnvFromShell (env) { } let result = {} - for (let line of stdout.split('\n')) { + for (let line of stdout.split('\0')) { if (line.includes('=')) { let components = line.split('=') let key = components.shift()