зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1352893: Handle non-UTF-8 data in Unix environment variables. r=mstange
MozReview-Commit-ID: 5aRVYQICc7O --HG-- extra : rebase_source : 6244a8ba08bad6da90496f27e9bb4eaace5e6fb9 extra : amend_source : f997353c8b075c989ace2790ae73330fd375b558
This commit is contained in:
Родитель
1fd72486a0
Коммит
0638745d18
|
@ -18,6 +18,8 @@ let EXPORTED_SYMBOLS = ["Subprocess"];
|
|||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.importGlobalProperties(["TextEncoder"]);
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm");
|
||||
|
@ -30,6 +32,19 @@ if (AppConstants.platform == "win") {
|
|||
"resource://gre/modules/subprocess/subprocess_unix.jsm");
|
||||
}
|
||||
|
||||
function encodeEnvVar(name, value) {
|
||||
if (typeof name === "string" && typeof value === "string") {
|
||||
return `${name}=${value}`;
|
||||
}
|
||||
|
||||
let encoder = new TextEncoder("utf-8");
|
||||
function encode(val) {
|
||||
return typeof val === "string" ? encoder.encode(val) : val;
|
||||
}
|
||||
|
||||
return Uint8Array.of(...encode(name), ...encode("="), ...encode(value), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows for creation of and communication with OS-level sub-processes.
|
||||
* @namespace
|
||||
|
@ -102,8 +117,8 @@ var Subprocess = {
|
|||
Object.assign(environment, options.environment);
|
||||
}
|
||||
|
||||
options.environment = Object.keys(environment)
|
||||
.map(key => `${key}=${environment[key]}`);
|
||||
options.environment = Object.entries(environment)
|
||||
.map(([key, val]) => encodeEnvVar(key, val));
|
||||
|
||||
options.arguments = Array.from(options.arguments || []);
|
||||
|
||||
|
|
|
@ -41,6 +41,14 @@ var libc = new Library("libc", LIBC_CHOICES, {
|
|||
ctypes.char.ptr.ptr.ptr,
|
||||
],
|
||||
|
||||
setenv: [
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.char.ptr,
|
||||
ctypes.char.ptr,
|
||||
ctypes.int,
|
||||
],
|
||||
|
||||
chdir: [
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.importGlobalProperties(["TextDecoder"]);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["SubprocessImpl"];
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
@ -76,6 +78,21 @@ class Process extends BaseProcess {
|
|||
}
|
||||
}
|
||||
|
||||
// Convert a null-terminated char pointer into a sized char array, and then
|
||||
// convert that into a JS typed array.
|
||||
// The resulting array will not be null-terminated.
|
||||
function ptrToUint8Array(input) {
|
||||
let {cast, uint8_t} = ctypes;
|
||||
|
||||
let len = 0;
|
||||
for (let ptr = cast(input, uint8_t.ptr); ptr.contents; ptr = ptr.increment()) {
|
||||
len++;
|
||||
}
|
||||
|
||||
let aryPtr = cast(input, uint8_t.array(len).ptr);
|
||||
return new Uint8Array(aryPtr.contents);
|
||||
}
|
||||
|
||||
var SubprocessUnix = {
|
||||
Process,
|
||||
|
||||
|
@ -91,13 +108,26 @@ var SubprocessUnix = {
|
|||
environ = libc.environ;
|
||||
}
|
||||
|
||||
for (let envp = environ; !envp.contents.isNull(); envp = envp.increment()) {
|
||||
let str = envp.contents.readString();
|
||||
const EQUAL = "=".charCodeAt(0);
|
||||
let decoder = new TextDecoder("utf-8", {fatal: true});
|
||||
|
||||
let idx = str.indexOf("=");
|
||||
if (idx >= 0) {
|
||||
yield [str.slice(0, idx),
|
||||
str.slice(idx + 1)];
|
||||
function decode(array) {
|
||||
try {
|
||||
return decoder.decode(array);
|
||||
} catch (e) {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
for (let envp = environ; !envp.contents.isNull(); envp = envp.increment()) {
|
||||
let buf = ptrToUint8Array(envp.contents);
|
||||
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
if (buf[i] == EQUAL) {
|
||||
yield [decode(buf.subarray(0, i)),
|
||||
decode(buf.subarray(i + 1))];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -146,7 +176,7 @@ var SubprocessUnix = {
|
|||
}
|
||||
|
||||
let dirs = [];
|
||||
if (environment.PATH) {
|
||||
if (typeof environment.PATH === "string") {
|
||||
dirs = environment.PATH.split(":");
|
||||
}
|
||||
|
||||
|
|
|
@ -716,6 +716,33 @@ add_task(function* test_subprocess_environmentAppend() {
|
|||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
if (AppConstants.platform !== "win") {
|
||||
add_task(function* test_subprocess_nonASCII() {
|
||||
const {libc} = Cu.import("resource://gre/modules/subprocess/subprocess_unix.jsm", {});
|
||||
|
||||
// Use TextDecoder rather than a string with a \xff escape, since
|
||||
// the latter will automatically be normalized to valid UTF-8.
|
||||
let val = new TextDecoder().decode(Uint8Array.of(1, 255));
|
||||
|
||||
libc.setenv("FOO", Uint8Array.from(val + "\0", c => c.charCodeAt(0)), 1);
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "FOO"],
|
||||
});
|
||||
|
||||
let foo = yield read(proc.stdout);
|
||||
|
||||
equal(foo, val, "Got expected $FOO value");
|
||||
|
||||
env.set("FOO", "");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_bad_executable() {
|
||||
// Test with a non-executable file.
|
||||
|
|
Загрузка…
Ссылка в новой задаче