Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test-hash-seed fails #231

Closed
targos opened this issue Jun 24, 2022 · 7 comments
Closed

test-hash-seed fails #231

targos opened this issue Jun 24, 2022 · 7 comments

Comments

@targos
Copy link
Member

targos commented Jun 24, 2022

https://github.com/nodejs/node-v8/runs/7037723725?check_suite_focus=true

Path: pummel/test-hash-seed
Error: --- stderr ---
node:internal/errors:856
  const err = new Error(message);
              ^
Error: Command failed: /home/runner/work/node-v8/node-v8/out/Release/node /home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js
/home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js:163
  throw new Error('no candidates remaining');
  ^
Error: no candidates remaining
    at Object.<anonymous> (/home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js:163:9)
    at Module._compile (node:internal/modules/cjs/loader:1116:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1170:10)
    at Module.load (node:internal/modules/cjs/loader:994:32)
    at Module._load (node:internal/modules/cjs/loader:834:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47
Node.js v19.0.0-pre
    at ChildProcess.exithandler (node:child_process:389:12)
    at ChildProcess.emit (node:events:537:28)
    at maybeClose (node:internal/child_process:1091:16)
    at ChildProcess._handle.onexit (node:internal/child_process:302:5) {
  code: 1,
  killed: false,
  signal: null,
  cmd: '/home/runner/work/node-v8/node-v8/out/Release/node /home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js',
  stdout: '',
  stderr: '/home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js:163\n' +
    "  throw new Error('no candidates remaining');\n" +
    '  ^\n' +
    '\n' +
    'Error: no candidates remaining\n' +
    '    at Object.<anonymous> (/home/runner/work/node-v8/node-v8/test/fixtures/guess-hash-seed.js:163:9)\n' +
    '    at Module._compile (node:internal/modules/cjs/loader:1116:14)\n' +
    '    at Module._extensions..js (node:internal/modules/cjs/loader:1170:10)\n' +
    '    at Module.load (node:internal/modules/cjs/loader:994:32)\n' +
    '    at Module._load (node:internal/modules/cjs/loader:834:12)\n' +
    '    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)\n' +
    '    at node:internal/main/run_main_module:17:47\n' +
    '\n' +
    'Node.js v19.0.0-pre\n'
}
Node.js v19.0.0-pre
Command: out/Release/node /home/runner/work/node-v8/node-v8/test/pummel/test-hash-seed.js
@targos
Copy link
Member Author

targos commented Jun 24, 2022

So, it seems that the hash seed cannot be guessed anymore? I don't know who to ping about that @nodejs/v8

@camillobruni
Copy link

I don't think we have any guarantee on what hashing function / seeds we use internally in V8.
What's the purpose of this test actually?

@targos
Copy link
Member Author

targos commented Jun 24, 2022

The test verifies that two Node.js processes do not use the same hash seed.
It's related to this security release: https://nodejs.org/en/blog/vulnerability/july-2017-security-releases/#node-js-specific-security-flaws

@bnoordhuis
Copy link
Member

I didn't look too deeply into this but that test learns the hash seed by observing insertion time into a Set.

It leans heavily on the observation that set.has(value) was an ersatz compiler barrier to V8. If V8 learned to optimize around has() calls, then that probably throws off the timing enough to stop the algorithm from converging.

I was going to suggest starting node with --noopt but when I tried that locally, it ran so slow I gave up after 10 minutes.

@targos
Copy link
Member Author

targos commented Jul 11, 2022

I'm able to make the test pass again with the following changes:

diff --git a/test/fixtures/guess-hash-seed.js b/test/fixtures/guess-hash-seed.js
index 8d69cf9249..c6166450b4 100644
--- a/test/fixtures/guess-hash-seed.js
+++ b/test/fixtures/guess-hash-seed.js
@@ -67,9 +67,6 @@ function hash_to_bucket(hash, numBuckets) {
 function time_set_lookup(set, value) {
   const t1 = process.hrtime();
   for (let i = 0; i < 100; i++) {
-    // annoyingly, SetHas() is JS code and therefore potentially optimizable.
-    // However, SetHas() looks up the table using native code, and it seems like
-    // that's sufficient to prevent the optimizer from doing anything?
     set.has(value);
   }
   const t = process.hrtime(t1);
@@ -78,6 +75,9 @@ function time_set_lookup(set, value) {
   return secs * 1e9 + nanos;
 }

+// Prevent optimization of SetHas().
+%NeverOptimizeFunction(time_set_lookup);
+
 // Set with 256 buckets; bucket 0 full, others empty
 const tester_set_buckets = 256;
 const tester_set = new Set();
diff --git a/test/pummel/test-hash-seed.js b/test/pummel/test-hash-seed.js
index 274183d8ce..95ad87d4d8 100644
--- a/test/pummel/test-hash-seed.js
+++ b/test/pummel/test-hash-seed.js
@@ -24,7 +24,14 @@ const requiredCallback = common.mustCall((results) => {
   assert.strictEqual(seeds.length, kRepetitions);
 });

-const generateSeed = () => execFilePromise(process.execPath, [targetScript]);
+function generateSeed() {
+  return execFilePromise(process.execPath, [
+    // Needed for %NeverOptimizeFunction.
+    '--allow-natives-syntax',
+    targetScript
+  ]);
+}
+
 const subprocesses = [...new Array(kRepetitions)].map(generateSeed);

 Promise.all(subprocesses)

Is that acceptable?

@camillobruni
Copy link

I guess that will work.
However, we generally don't have any guarantees for --allow-natives-syntax and this might break at any point in the future.

@targos
Copy link
Member Author

targos commented Jul 12, 2022

Done, thank you.

@targos targos closed this as completed Jul 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants