ww: preserve original environment for directory tests
This commit is contained in:
@@ -116,6 +116,11 @@ fn pkgallocstrs(cap: i32) ([]str | nomem) = {
|
||||
return value;
|
||||
};
|
||||
|
||||
fn pkgalloci32(cap: i32) ([]i32 | nomem) = {
|
||||
let value: []i32 = alloc([], cap: u64)?;
|
||||
return value;
|
||||
};
|
||||
|
||||
fn pkgallocbytes(cap: i32) ([]u8 | nomem) = {
|
||||
let value: []u8 = alloc([], cap: u64)?;
|
||||
return value;
|
||||
@@ -268,11 +273,81 @@ fn pkgfreestrs(values: []str) void = {
|
||||
};
|
||||
};
|
||||
|
||||
// Go's AppendPATH and AppendPWD append, then os/exec keeps the last duplicate
|
||||
// values. WW's executor preserves duplicates, so discard earlier exact entries
|
||||
// and materialize the selected driver's sibling directory first in PATH.
|
||||
fn runenv(tmpdir: str, pwd: str, builder: str, out: *[]str, tmpowned: *str,
|
||||
pathowned: *str, pwdowned: *str) bool = {
|
||||
fn pkgenvkeylen(entry: str) i32 = {
|
||||
let i: i32 = 0;
|
||||
for (i < entry.len) {
|
||||
if (entry[i] == '=') { return i; };
|
||||
i += 1;
|
||||
};
|
||||
return -1;
|
||||
};
|
||||
|
||||
fn pkgenvkeyequal(a: str, an: i32, b: str, bn: i32) bool = {
|
||||
if (an != bn) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < an) {
|
||||
if (a[i] != b[i]) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
fn pkgenvkeyis(entry: str, n: i32, name: str) bool = {
|
||||
return pkgenvkeyequal(entry, n, name, name.len);
|
||||
};
|
||||
|
||||
fn pkgenvhash(entry: str, n: i32) u64 = {
|
||||
let h: u64 = 14695981039346656037u64;
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
h = h ^ (entry[i]: u64);
|
||||
h = h * 1099511628211u64;
|
||||
i += 1;
|
||||
};
|
||||
return h;
|
||||
};
|
||||
|
||||
fn pkgenvtablecap(entries: i32) i32 = {
|
||||
if (entries == 0) { return 0; };
|
||||
if (entries > PKG_COUNT_MAX / 2) { return -1; };
|
||||
let need: i32 = entries * 2;
|
||||
let cap: i32 = PKG_INITIAL_CAP;
|
||||
for (cap < need) {
|
||||
if (cap > PKG_COUNT_MAX / 2) { return -1; };
|
||||
cap *= 2;
|
||||
};
|
||||
return cap;
|
||||
};
|
||||
|
||||
// Go snapshots user-test variables through Unix os.Environ before appending
|
||||
// PATH and PWD. WW's raw environment walker and executor do no such duplicate
|
||||
// normalization, so the launch owner must materialize that snapshot itself.
|
||||
fn pkgenvfirst(slots: []i32, inherited: []str, at: i32, n: i32) bool = {
|
||||
let slot: i32 = (pkgenvhash(inherited[at], n)
|
||||
% (slots.len: u64)): i32;
|
||||
let probes: i32 = 0;
|
||||
for (probes < slots.len) {
|
||||
let prior: i32 = slots[slot];
|
||||
if (prior < 0) {
|
||||
slots[slot] = at;
|
||||
return true;
|
||||
};
|
||||
let priorn: i32 = pkgenvkeylen(inherited[prior]);
|
||||
if (pkgenvkeyequal(inherited[at], n,
|
||||
inherited[prior], priorn)) {
|
||||
return false;
|
||||
};
|
||||
slot += 1;
|
||||
if (slot == slots.len) { slot = 0; };
|
||||
probes += 1;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// Go's appended PATH and PWD survive os/exec's later-value selection. WW's
|
||||
// executor preserves its concrete vector, so inherited copies are excluded.
|
||||
fn runenv(pwd: str, builder: str, out: *[]str, pathowned: *str,
|
||||
pwdowned: *str) bool = {
|
||||
let toolbin: str;
|
||||
let oom: bool = false;
|
||||
if (!pkgcanonicaldir(pkgdirname(builder), &toolbin, &oom)) {
|
||||
@@ -283,35 +358,71 @@ fn runenv(tmpdir: str, pwd: str, builder: str, out: *[]str, tmpowned: *str,
|
||||
return false;
|
||||
};
|
||||
let inherited: []str = os.getenvs();
|
||||
if (inherited.len > PKG_COUNT_MAX - 4) {
|
||||
if (inherited.len > PKG_COUNT_MAX - 2) {
|
||||
pkgputln(os.STDERR_FILENO,
|
||||
"wwtest package: package graph is too large");
|
||||
return false;
|
||||
};
|
||||
let allocation: ([]str | nomem) = pkgallocstrs(inherited.len + 4);
|
||||
let allocation: ([]str | nomem) = pkgallocstrs(inherited.len + 2);
|
||||
let env: []str;
|
||||
match (allocation) {
|
||||
case let value: []str => env = value;
|
||||
case nomem => {
|
||||
pkgputln(os.STDERR_FILENO, "wwtest package: out of memory");
|
||||
return false;
|
||||
};
|
||||
};
|
||||
};
|
||||
let keyed: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < inherited.len) {
|
||||
if (!strings.hasprefix(inherited[i], "TMPDIR=")
|
||||
&& !strings.hasprefix(inherited[i], "LC_ALL=")
|
||||
&& !strings.hasprefix(inherited[i], "PATH=")
|
||||
&& !strings.hasprefix(inherited[i], "PWD=")) {
|
||||
let n: i32 = pkgenvkeylen(inherited[i]);
|
||||
if (n >= 0 && !pkgenvkeyis(inherited[i], n, "PATH")
|
||||
&& !pkgenvkeyis(inherited[i], n, "PWD")) {
|
||||
keyed += 1;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
let tablecap: i32 = pkgenvtablecap(keyed);
|
||||
if (tablecap < 0) {
|
||||
pkgputln(os.STDERR_FILENO,
|
||||
"wwtest package: package graph is too large");
|
||||
pkgfreestrs(env);
|
||||
return false;
|
||||
};
|
||||
let slots: []i32;
|
||||
slots.ptr = nil: *i32;
|
||||
slots.len = 0;
|
||||
slots.cap = 0;
|
||||
if (tablecap != 0) {
|
||||
let tableallocation: ([]i32 | nomem) = pkgalloci32(tablecap);
|
||||
match (tableallocation) {
|
||||
case let value: []i32 => slots = value;
|
||||
case nomem => {
|
||||
pkgputln(os.STDERR_FILENO,
|
||||
"wwtest package: out of memory");
|
||||
pkgfreestrs(env);
|
||||
return false;
|
||||
};
|
||||
};
|
||||
slots.len = tablecap;
|
||||
i = 0;
|
||||
for (i < slots.len) { slots[i] = -1; i += 1; };
|
||||
};
|
||||
i = 0;
|
||||
for (i < inherited.len) {
|
||||
let n: i32 = pkgenvkeylen(inherited[i]);
|
||||
if (n < 0) {
|
||||
if (inherited[i].len != 0) { append(env, inherited[i]); };
|
||||
} else if (!pkgenvkeyis(inherited[i], n, "PATH")
|
||||
&& !pkgenvkeyis(inherited[i], n, "PWD")
|
||||
&& pkgenvfirst(slots, inherited, i, n)) {
|
||||
append(env, inherited[i]);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
append(env, "LC_ALL=C");
|
||||
let tmpenv: str;
|
||||
if (!pkgstring(&tmpenv, "TMPDIR=", tmpdir)) {
|
||||
pkgfreestrs(env);
|
||||
return false;
|
||||
if (slots.ptr != nil) {
|
||||
os.free(slots.ptr: *void,
|
||||
(slots.cap: u64) * (size(i32): u64));
|
||||
};
|
||||
let pathenv: str;
|
||||
let pathok: bool = false;
|
||||
@@ -327,29 +438,24 @@ fn runenv(tmpdir: str, pwd: str, builder: str, out: *[]str, tmpowned: *str,
|
||||
case void => pathok = pkgstring(&pathenv, "PATH=", toolbin);
|
||||
};
|
||||
if (!pathok) {
|
||||
pkgfreeownedstr(tmpenv);
|
||||
pkgfreestrs(env);
|
||||
return false;
|
||||
};
|
||||
let pwdenv: str;
|
||||
if (!pkgstring(&pwdenv, "PWD=", pwd)) {
|
||||
pkgfreeownedstr(tmpenv);
|
||||
pkgfreeownedstr(pathenv);
|
||||
pkgfreestrs(env);
|
||||
return false;
|
||||
};
|
||||
append(env, tmpenv);
|
||||
append(env, pathenv);
|
||||
append(env, pwdenv);
|
||||
*out = env;
|
||||
*tmpowned = tmpenv;
|
||||
*pathowned = pathenv;
|
||||
*pwdowned = pwdenv;
|
||||
return true;
|
||||
};
|
||||
|
||||
fn freerunenv(env: []str, tmpowned: str, pathowned: str, pwdowned: str) void = {
|
||||
pkgfreeownedstr(tmpowned);
|
||||
fn freerunenv(env: []str, pathowned: str, pwdowned: str) void = {
|
||||
pkgfreeownedstr(pathowned);
|
||||
pkgfreeownedstr(pwdowned);
|
||||
pkgfreestrs(env);
|
||||
@@ -1624,11 +1730,9 @@ fn pkgstartrun(g: *pkggroup, filters: []str, timeoutarg: str,
|
||||
let i: i32 = 0;
|
||||
for (i < filters.len) { append(ra, filters[i]); i += 1; };
|
||||
let env: []str;
|
||||
let tmpowned: str;
|
||||
let pathowned: str;
|
||||
let pwdowned: str;
|
||||
if (!runenv(g.root, g.dir, builder, &env, &tmpowned,
|
||||
&pathowned, &pwdowned)) {
|
||||
if (!runenv(g.dir, builder, &env, &pathowned, &pwdowned)) {
|
||||
pkgfreeownedstr(packagearg);
|
||||
pkgfreestrs(ra);
|
||||
return false;
|
||||
@@ -1644,7 +1748,7 @@ fn pkgstartrun(g: *pkggroup, filters: []str, timeoutarg: str,
|
||||
rcmd.deadline.nsec = 0i64;
|
||||
rcmd.grace = 0i64: time.duration;
|
||||
exec.start(h, &rcmd);
|
||||
freerunenv(env, tmpowned, pathowned, pwdowned);
|
||||
freerunenv(env, pathowned, pwdowned);
|
||||
pkgfreeownedstr(packagearg);
|
||||
pkgfreestrs(ra);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user