From a1755e3aa1888609b2562351f28fd168c03b6209 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 31 Jan 2020 20:06:56 +0100 Subject: [PATCH] worker: reset `Isolate` stack limit after entering `Locker` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that using `v8::Locker` undoes the effects of passing an explicit stack limit as part of the `Isolate`’s resource constraints. Therefore, reset the stack limit manually after entering a Locker. Refs: https://github.com/nodejs/node/pull/26049#issuecomment-580668530 --- src/node_worker.cc | 7 ++++ .../test-worker-stack-overflow-stack-size.js | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/parallel/test-worker-stack-overflow-stack-size.js diff --git a/src/node_worker.cc b/src/node_worker.cc index b350219d813832..85c110061e0094 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -157,6 +157,9 @@ class WorkerThreadData { { Locker locker(isolate); Isolate::Scope isolate_scope(isolate); + // V8 computes its stack limit every time a `Locker` is used based on + // --stack-size. Reset it to the correct value. + isolate->SetStackLimit(w->stack_base_); HandleScope handle_scope(isolate); isolate_data_.reset(CreateIsolateData(isolate, @@ -242,6 +245,10 @@ void Worker::Run() { { Locker locker(isolate_); Isolate::Scope isolate_scope(isolate_); + // V8 computes its stack limit every time a `Locker` is used based on + // --stack-size. Reset it to the correct value. + isolate_->SetStackLimit(stack_base_); + SealHandleScope outer_seal(isolate_); DeleteFnPtr env_; diff --git a/test/parallel/test-worker-stack-overflow-stack-size.js b/test/parallel/test-worker-stack-overflow-stack-size.js new file mode 100644 index 00000000000000..3d2c23acbe01ac --- /dev/null +++ b/test/parallel/test-worker-stack-overflow-stack-size.js @@ -0,0 +1,40 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { once } = require('events'); +const v8 = require('v8'); +const { Worker } = require('worker_threads'); + +// Verify that Workers don't care about --stack-size, as they have their own +// fixed and known stack sizes. + +async function runWorker() { + const empiricalStackDepth = new Uint32Array(new SharedArrayBuffer(4)); + const worker = new Worker(` + const { workerData: { empiricalStackDepth } } = require('worker_threads'); + function f() { + empiricalStackDepth[0]++; + f(); + } + f();`, { + eval: true, + workerData: { empiricalStackDepth } + }); + + const [ error ] = await once(worker, 'error'); + + common.expectsError({ + constructor: RangeError, + message: 'Maximum call stack size exceeded' + })(error); + + return empiricalStackDepth[0]; +} + +(async function() { + v8.setFlagsFromString('--stack-size=500'); + const w1stack = await runWorker(); + v8.setFlagsFromString('--stack-size=1000'); + const w2stack = await runWorker(); + assert.strictEqual(w1stack, w2stack); +})().then(common.mustCall());