diff --git a/src/node_webstorage.cc b/src/node_webstorage.cc index 10c3ccd68e49a1..21f846fbeb6225 100644 --- a/src/node_webstorage.cc +++ b/src/node_webstorage.cc @@ -43,6 +43,7 @@ using v8::PropertyAttribute; using v8::PropertyCallbackInfo; using v8::PropertyDescriptor; using v8::PropertyHandlerFlags; +using v8::Signature; using v8::String; using v8::Value; @@ -737,8 +738,9 @@ static void Initialize(Local target, Local(), PropertyHandlerFlags::kHasNoSideEffect)); - Local length_getter = - FunctionTemplate::New(isolate, StorageLengthGetter); + Local length_signature = Signature::New(isolate, ctor_tmpl); + Local length_getter = FunctionTemplate::New( + isolate, StorageLengthGetter, Local(), length_signature); ctor_tmpl->PrototypeTemplate()->SetAccessorProperty(env->length_string(), length_getter, Local(), diff --git a/test/parallel/test-webstorage.js b/test/parallel/test-webstorage.js index 71e0a095163ced..affa9099ed3ec2 100644 --- a/test/parallel/test-webstorage.js +++ b/test/parallel/test-webstorage.js @@ -26,6 +26,21 @@ test('Storage instances cannot be created in userland', async () => { assert.match(cp.stderr, /Error: Illegal constructor/); }); +test('reading "length" on Storage.prototype throws instead of crashing', async () => { + // Refs: the `length` getter is defined on Storage.prototype but used to lack + // a signature, so accessing it on the prototype (not a real Storage instance) + // unwrapped a non-Storage object and segfaulted. + const cp = await spawnPromisified(process.execPath, [ + '-e', + 'globalThis.sessionStorage.setItem.length;globalThis.Storage.prototype.length', + ]); + + assert.strictEqual(cp.signal, null); + assert.strictEqual(cp.code, 1); + assert.strictEqual(cp.stdout, ''); + assert.match(cp.stderr, /Illegal invocation/); +}); + test('sessionStorage is not persisted', async () => { let cp = await spawnPromisified(process.execPath, [ '-pe', 'sessionStorage.foo = "barbaz"',