@andersbakken/fisk 5.0.12 → 5.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3039,6 +3039,16 @@ var fs = libExports;
3039
3039
  const FISK_PAD_LENGTH = 4096;
3040
3040
  const FISK_NAME_PAD = "/fisk-name" + "_".repeat(FISK_PAD_LENGTH - "/fisk-name".length);
3041
3041
  const FISK_CDIR_PAD = "/fisk-cdir" + "_".repeat(FISK_PAD_LENGTH - "/fisk-cdir".length);
3042
+ // Flags asking the compiler to record its own argv, mapped to the negation the
3043
+ // same compiler spells it with. -g* forms land in DW_AT_producer, -f* forms in a
3044
+ // .GCC.command.line section; clang uses the command-line names and also accepts
3045
+ // the gcc-switches ones as aliases.
3046
+ const RECORD_FLAG_NEGATIONS = {
3047
+ "-grecord-command-line": "-gno-record-command-line",
3048
+ "-frecord-command-line": "-fno-record-command-line",
3049
+ "-grecord-gcc-switches": "-gno-record-gcc-switches",
3050
+ "-frecord-gcc-switches": "-fno-record-gcc-switches"
3051
+ };
3042
3052
  class Compile extends EventEmitter__default["default"] {
3043
3053
  constructor(args, argv0, dir, debug, sourceFileName, paddedPaths) {
3044
3054
  super();
@@ -3165,20 +3175,52 @@ class Compile extends EventEmitter__default["default"] {
3165
3175
  throw new Error("No sourcefile");
3166
3176
  }
3167
3177
  const sourceFileInDir = path__default["default"].join(dir, sourceFileName || path__default["default"].basename(sourcePath));
3178
+ // Padding only pays off where the client's byte scan can reach the pads,
3179
+ // and it is only *needed* for LLVM bitcode, which DwarfPatcher cannot
3180
+ // load. Everywhere else DwarfPatcher already works, and padding actively
3181
+ // breaks it: it matches on the old /compiles path still being in
3182
+ // .debug_str, so once the pads have replaced it there is nothing for the
3183
+ // fallback to match and the pads stay in the debug info.
3184
+ //
3185
+ // - non-clang: gcc never emits bitcode, and some gcc builds (the nrdp
3186
+ // desktop toolchain, for one) compress .debug_str by default with no
3187
+ // flag asking for it, which the byte scan cannot see into.
3188
+ // - -gz: same problem, explicitly requested. -Wl, forms are link-time
3189
+ // and do not affect the object we hand back, so they do not count.
3190
+ const wantsCompressedDebug = args.some((arg) => {
3191
+ if (arg.startsWith("-Wl,")) {
3192
+ return false;
3193
+ }
3194
+ return (arg.startsWith("-gz") && arg !== "-gz=none") || arg.includes("compress-debug-sections");
3195
+ });
3196
+ if (paddedPaths && (!isClang || wantsCompressedDebug)) {
3197
+ if (debug) {
3198
+ console.log("Not padding paths, leaving them to DwarfPatcher:", "isClang", isClang, "wantsCompressedDebug", wantsCompressedDebug);
3199
+ }
3200
+ paddedPaths = false;
3201
+ }
3168
3202
  if (paddedPaths) {
3169
- // -grecord-command-line embeds our own argv verbatim into
3170
- // DW_AT_producer, which would (a) add two PATH_MAX pads to every CU
3171
- // and (b) leave the builder's /compiles path in the producer, where
3172
- // the client's byte scan would hit the embedded pad and NUL-truncate
3173
- // the rest of the recorded command line. The recorded line would be
3174
- // the builder's rewritten argv anyway -- not the client's -- so drop
3175
- // it rather than record something both wrong and mangled.
3176
- for (let i = args.length - 1; i >= 0; --i) {
3177
- if (args[i] === "-grecord-command-line" || args[i] === "-frecord-command-line") {
3178
- args.splice(i, 1);
3203
+ // -grecord-command-line (clang) / -frecord-gcc-switches (gcc) embed
3204
+ // our own argv verbatim into DW_AT_producer or .GCC.command.line,
3205
+ // which would (a) add two PATH_MAX pads to every CU and (b) leave
3206
+ // the builder's /compiles path in there, where the client's byte
3207
+ // scan would hit the embedded pad and NUL-truncate the rest of the
3208
+ // recorded command line. The recorded line would be the builder's
3209
+ // rewritten argv anyway -- not the client's -- so turn it off rather
3210
+ // than record something both wrong and mangled.
3211
+ //
3212
+ // Negate each flag in place instead of dropping it and appending one
3213
+ // fixed negation: whichever compiler accepted the positive spelling
3214
+ // necessarily accepts its own negation, whereas a fixed flag is a
3215
+ // guess about the compiler. That guess is what put
3216
+ // -gno-record-command-line (clang 11+, and gcc spells it
3217
+ // -gno-record-gcc-switches) on gcc command lines.
3218
+ for (let i = 0; i < args.length; ++i) {
3219
+ const negation = RECORD_FLAG_NEGATIONS[args[i]];
3220
+ if (negation) {
3221
+ args[i] = negation;
3179
3222
  }
3180
3223
  }
3181
- args.push("-gno-record-command-line");
3182
3224
  // The more specific source-file rule must come last: both clang and
3183
3225
  // gcc let a later -fdebug-prefix-map win over an earlier one, and
3184
3226
  // the directory rule is a prefix of the source-file rule.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andersbakken/fisk",
3
- "version": "5.0.12",
3
+ "version": "5.0.13",
4
4
  "description": "Fisk, a distributed compile system",
5
5
  "scripts": {
6
6
  "lint": "eslint . --ext .ts",
@@ -57998,7 +57998,31 @@ const option = options({
57998
57998
  const common = common$1(option);
57999
57999
  let nextCommandId = 0;
58000
58000
  const server = new Server(option, common.Version);
58001
- const clientMinimumVersion = "5.0.6";
58001
+ // 5.0.11 is the first client that asks for padded paths and can patch them out
58002
+ // of LTO bitcode. An older client silently produces objects with the builder's
58003
+ // /compiles paths baked into the debug info -- and because paddedPaths is not
58004
+ // part of the object cache key, those objects are then served to up-to-date
58005
+ // clients too, so one stale client poisons everyone's backtraces.
58006
+ const clientMinimumVersion = "5.0.11";
58007
+ // compareVersions throws on an empty or malformed version rather than returning
58008
+ // an ordering, and npmVersion is "" for any client that sends no
58009
+ // x-fisk-npm-version header. Thrown out of the compile handler that would be a
58010
+ // silent hang: uncaughtException keeps the scheduler up, but the request is
58011
+ // abandoned half-handled, so the client waits for a reply that never comes
58012
+ // instead of being told to update. A version we cannot read is not >= the
58013
+ // minimum, so treat it as too old and reject it properly.
58014
+ function clientTooOld(npmVersion) {
58015
+ if (!npmVersion) {
58016
+ return true;
58017
+ }
58018
+ try {
58019
+ return compareVersions(clientMinimumVersion, npmVersion) >= 1;
58020
+ }
58021
+ catch (err) {
58022
+ console.error(`Unparseable client npm version: "${npmVersion}"`, err);
58023
+ return true;
58024
+ }
58025
+ }
58002
58026
  const serverStartTime = Date.now();
58003
58027
  // A stalled event loop stops calling accept(), the listen backlog fills and the
58004
58028
  // kernel then silently drops SYNs, which clients see as a connect timeout rather
@@ -58848,7 +58872,7 @@ function requestEnvironment(compile) {
58848
58872
  return true;
58849
58873
  }
58850
58874
  server.on("clientVerify", (clientVerify) => {
58851
- if (compareVersions(clientMinimumVersion, clientVerify.npmVersion) >= 1) {
58875
+ if (clientTooOld(clientVerify.npmVersion)) {
58852
58876
  clientVerify.send("version_mismatch", { minimum_version: `${clientMinimumVersion}` });
58853
58877
  }
58854
58878
  else {
@@ -58859,7 +58883,7 @@ server.on("compile", (compile) => {
58859
58883
  compile.on("log", (event) => {
58860
58884
  addLogFile({ source: "client", ip: compile.ip, contents: event.message });
58861
58885
  });
58862
- if (compareVersions(clientMinimumVersion, compile.npmVersion) >= 1) {
58886
+ if (clientTooOld(compile.npmVersion)) {
58863
58887
  ++jobsFailed;
58864
58888
  compile.send("version_mismatch", { minimum_version: `${clientMinimumVersion}` });
58865
58889
  return;