Repository navigation
inspector: avoid more JS calls from V8 interrupts - #66740
christianaurichzm wants to merge 3 commits into
Conversation
|
Review requested:
|
|
@legendecas @joyeecheung since you reviewed #65397, could you take a look at the re-land when you get a chance? It also needs a node-test-commit-v8-linux run, since that is what caught the futex failure last time. Thanks! |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #66740 +/- ##
==========================================
- Coverage 92.85% 90.51% -2.34%
==========================================
Files 428 797 +369
Lines 194693 278377 +83684
Branches 30091 53489 +23398
==========================================
+ Hits 180774 251970 +71196
- Misses 13593 16794 +3201
- Partials 326 9613 +9287
🚀 New features to boost your workflow:
|
|
Oh another case found,
Rather than deferring |
|
Note that we are drafting a new policy for updating V8 in Node.js - for V8 commit backports that are justified to be fast tracked and do not have to wait for the regular V8 upgrade, it's better to target release staging branches, instead of main: #66710 |
Inspector messages for a main thread connection are dispatched from a V8 interrupt handler. Defer frontend messages in this case using a microtask. This preserves the existing timing contract for main thread inspector connections, where notifications are observable after a microtask checkpoint. Starting the inspector I/O thread and toggling network tracking can also call into JS from an interrupt. Signed-off-by: deepak1556 <hop2deep@gmail.com> Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
960398c to
3090ade
Compare
|
Thanks @joyeecheung. I dropped the backport and the commit that enables the check. I'll enable it in a separate PR once a V8 update brings in v8/v8@35bd1582fe0a. @deepak1556, you're right about the second case: with a I tried your patch with the check enabled and both cases work. One thing I hit: BindingData* binding_data = realm->GetBindingData<BindingData>();
if (binding_data != nullptr && args[2]->IsBoolean()) {
auto& slot = args[2]->IsTrue() ? binding_data->local_storage
: binding_data->session_storage;
slot = BaseObjectWeakPtr<Storage>(storage);
}If you're OK with that change, I'll add your patch here with you as the author, plus regression tests. |
|
Thats a better check, thanks for catching it.
SGTM |
Protocol messages from a remote frontend are dispatched from a V8 API interrupt, where executing JavaScript is disallowed. DOMStorageAgent::getDOMStorageItems() previously looked up globalThis.localStorage and globalThis.sessionStorage via v8::Object::Get(), invoking their lazy JS getters on globalThis. In addition, Storage::GetAll() opened the backing store via Storage::Open(), which threw a JS Error on failure only for the inspector agent to catch it with v8::TryCatch. Track live Storage instances in webstorage::BindingData when the inspector subclasses construct them in Storage::New(), using the flag they pass to tell localStorage from sessionStorage, since both can be in memory. Check HasRealNamedCallbackProperty() before reading the global property so the lazy JS getter is not invoked during an interrupt. When the store has not yet been initialized by JS during an interrupt, read the SQLite backing file directly for localStorage and return an empty map for sessionStorage. Factor Storage::OpenConnection() to return open errors as a C++ string rather than throwing a JS exception in Storage::GetAll(). Co-authored-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com> Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
Read both stores over a remote session while the main thread runs JavaScript, so that the messages are dispatched from a V8 API interrupt: stores the application never touched, both stores in memory with sessionStorage created first, and a malformed localStorage file. The script counts calls to the storage getters and to an Error.prototype.code setter, so the test fails if a read calls into JavaScript even when V8 does not enforce it. Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
|
Thanks @deepak1556, I added it as the second commit with the One thing: your patch didn't have a |
This lands the Node.js side of #65397, which was reverted in #65907, without enabling the V8 check.
The first commit is @deepak1556's
inspector: defer JS execution from V8 interruptsfrom #65397, unchanged apart from a conflict with #65877. As before, messages for an in-processinspector.Sessionthat arrive while Node.js handles another client's message in an interrupt are delivered at the next microtask checkpoint instead of synchronously.The second commit is @deepak1556's patch from the discussion below.
DOMStorage.getDOMStorageItemsnow reads the stores without calling into JavaScript: from an interrupt it no longer goes through theglobalThis.localStorageandglobalThis.sessionStoragegetters, and a store that cannot be opened is reported without creating a JavaScript error. The third commit addstest-inspector-dom-storage-interrupt, which reads both stores from an interrupt and fails if any JavaScript runs there. It counts calls to the storage getters and to anError.prototype.codesetter, so it does not depend on the V8 check. Enabling the check needs v8/v8@35bd1582fe0a, which is in V8 15.8, so that will be a separate PR oncedeps/v8includes it.Each commit stands on its own, so this can land with
commit-queue-rebaseinstead of being squashed.Refs: #65397
Refs: #65907
Refs: #66710