diff --git a/build/util.cjs b/build/util.cjs index 1df79370d1..873ceb19d2 100644 --- a/build/util.cjs +++ b/build/util.cjs @@ -64,7 +64,7 @@ function preferLocalBin(env, ...dirs) { function quote(arg) { if (arg === "") return `$''`; if (/^[\w/.\-+@:=,%]+$/.test(arg)) return arg; - return `$'` + arg.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\f/g, "\\f").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\v/g, "\\v").replace(/\0/g, "\\0") + `'`; + return `$'` + arg.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\f/g, "\\f").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\v/g, "\\v").replace(/\0/g, "\\000") + `'`; } function quotePowerShell(arg) { if (arg === "") return `''`; diff --git a/src/util.ts b/src/util.ts index 1a272905ba..76b5ce0e87 100644 --- a/src/util.ts +++ b/src/util.ts @@ -86,7 +86,7 @@ export function quote(arg: string): string { .replace(/\r/g, '\\r') .replace(/\t/g, '\\t') .replace(/\v/g, '\\v') - .replace(/\0/g, '\\0') + + .replace(/\0/g, '\\000') + `'` ) } diff --git a/test/util.test.js b/test/util.test.js index fba510fcab..21da7c243a 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -70,13 +70,17 @@ describe('util', () => { test('quote()', () => { assert.ok(quote('string') === 'string') assert.ok(quote('') === `$''`) - assert.ok(quote(`'\f\n\r\t\v\0`) === `$'\\'\\f\\n\\r\\t\\v\\0'`) + assert.ok(quote(`'\f\n\r\t\v\0`) === `$'\\'\\f\\n\\r\\t\\v\\000'`) const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_/.-+@:=,%' assert.equal(quote(allowed), allowed) }) + test('quote() escapes null byte unambiguously', () => { + assert.equal(quote('\0' + '123'), `$'\\000123'`) + }) + test('quotePowerShell()', () => { assert.equal(quotePowerShell('string'), 'string') assert.equal(quotePowerShell(`'`), `''''`)