Skip to content

Commit 8c5ad13

Browse files
addaleaxBethGriggs
authored andcommitted
src: initialize inspector before RunBootstrapping()
This is necessary for `--inspect-brk-node` to work, and for the inspector to be aware of scripts created before bootstrapping. Fixes: #32648 Refs: #30467 (comment) PR-URL: #32672 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: David Carlier <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent ce79923 commit 8c5ad13

File tree

6 files changed

+85
-49
lines changed

6 files changed

+85
-49
lines changed

src/api/environment.cc

+28-28
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,19 @@ void FreeIsolateData(IsolateData* isolate_data) {
330330
delete isolate_data;
331331
}
332332

333+
InspectorParentHandle::~InspectorParentHandle() {}
334+
335+
// Hide the internal handle class from the public API.
336+
#if HAVE_INSPECTOR
337+
struct InspectorParentHandleImpl : public InspectorParentHandle {
338+
std::unique_ptr<inspector::ParentInspectorHandle> impl;
339+
340+
explicit InspectorParentHandleImpl(
341+
std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
342+
: impl(std::move(impl)) {}
343+
};
344+
#endif
345+
333346
Environment* CreateEnvironment(IsolateData* isolate_data,
334347
Local<Context> context,
335348
int argc,
@@ -348,7 +361,8 @@ Environment* CreateEnvironment(
348361
const std::vector<std::string>& args,
349362
const std::vector<std::string>& exec_args,
350363
EnvironmentFlags::Flags flags,
351-
ThreadId thread_id) {
364+
ThreadId thread_id,
365+
std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
352366
Isolate* isolate = context->GetIsolate();
353367
HandleScope handle_scope(isolate);
354368
Context::Scope context_scope(context);
@@ -365,6 +379,16 @@ Environment* CreateEnvironment(
365379
env->set_abort_on_uncaught_exception(false);
366380
}
367381

382+
#if HAVE_INSPECTOR
383+
if (inspector_parent_handle) {
384+
env->InitializeInspector(
385+
std::move(static_cast<InspectorParentHandleImpl*>(
386+
inspector_parent_handle.get())->impl));
387+
} else {
388+
env->InitializeInspector({});
389+
}
390+
#endif
391+
368392
if (env->RunBootstrapping().IsEmpty()) {
369393
FreeEnvironment(env);
370394
return nullptr;
@@ -394,19 +418,6 @@ void FreeEnvironment(Environment* env) {
394418
delete env;
395419
}
396420

397-
InspectorParentHandle::~InspectorParentHandle() {}
398-
399-
// Hide the internal handle class from the public API.
400-
#if HAVE_INSPECTOR
401-
struct InspectorParentHandleImpl : public InspectorParentHandle {
402-
std::unique_ptr<inspector::ParentInspectorHandle> impl;
403-
404-
explicit InspectorParentHandleImpl(
405-
std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
406-
: impl(std::move(impl)) {}
407-
};
408-
#endif
409-
410421
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
411422
Environment* env,
412423
ThreadId thread_id,
@@ -430,27 +441,17 @@ void LoadEnvironment(Environment* env) {
430441
MaybeLocal<Value> LoadEnvironment(
431442
Environment* env,
432443
StartExecutionCallback cb,
433-
std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
444+
std::unique_ptr<InspectorParentHandle> removeme) {
434445
env->InitializeLibuv(per_process::v8_is_profiling);
435446
env->InitializeDiagnostics();
436447

437-
#if HAVE_INSPECTOR
438-
if (inspector_parent_handle) {
439-
env->InitializeInspector(
440-
std::move(static_cast<InspectorParentHandleImpl*>(
441-
inspector_parent_handle.get())->impl));
442-
} else {
443-
env->InitializeInspector({});
444-
}
445-
#endif
446-
447448
return StartExecution(env, cb);
448449
}
449450

450451
MaybeLocal<Value> LoadEnvironment(
451452
Environment* env,
452453
const char* main_script_source_utf8,
453-
std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
454+
std::unique_ptr<InspectorParentHandle> removeme) {
454455
CHECK_NOT_NULL(main_script_source_utf8);
455456
return LoadEnvironment(
456457
env,
@@ -475,8 +476,7 @@ MaybeLocal<Value> LoadEnvironment(
475476
env->process_object(),
476477
env->native_module_require()};
477478
return ExecuteBootstrapper(env, name.c_str(), &params, &args);
478-
},
479-
std::move(inspector_parent_handle));
479+
});
480480
}
481481

482482
Environment* GetCurrentEnvironment(Local<Context> context) {

src/node.h

+11-7
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@ enum Flags : uint64_t {
420420
};
421421
} // namespace EnvironmentFlags
422422

423+
struct InspectorParentHandle {
424+
virtual ~InspectorParentHandle();
425+
};
426+
423427
// TODO(addaleax): Maybe move per-Environment options parsing here.
424428
// Returns nullptr when the Environment cannot be created e.g. there are
425429
// pending JavaScript exceptions.
@@ -436,16 +440,14 @@ NODE_EXTERN Environment* CreateEnvironment(
436440
const std::vector<std::string>& args,
437441
const std::vector<std::string>& exec_args,
438442
EnvironmentFlags::Flags flags = EnvironmentFlags::kDefaultFlags,
439-
ThreadId thread_id = {} /* allocates a thread id automatically */);
443+
ThreadId thread_id = {} /* allocates a thread id automatically */,
444+
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
440445

441-
struct InspectorParentHandle {
442-
virtual ~InspectorParentHandle();
443-
};
444446
// Returns a handle that can be passed to `LoadEnvironment()`, making the
445447
// child Environment accessible to the inspector as if it were a Node.js Worker.
446448
// `child_thread_id` can be created using `AllocateEnvironmentThreadId()`
447449
// and then later passed on to `CreateEnvironment()` to create the child
448-
// Environment.
450+
// Environment, together with the inspector handle.
449451
// This method should not be called while the parent Environment is active
450452
// on another thread.
451453
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
@@ -463,14 +465,16 @@ using StartExecutionCallback =
463465

464466
// TODO(addaleax): Deprecate this in favour of the MaybeLocal<> overload.
465467
NODE_EXTERN void LoadEnvironment(Environment* env);
468+
// The `InspectorParentHandle` arguments here are ignored and not used.
469+
// For passing `InspectorParentHandle`, use `CreateEnvironment()`.
466470
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
467471
Environment* env,
468472
StartExecutionCallback cb,
469-
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
473+
std::unique_ptr<InspectorParentHandle> ignored_donotuse_removeme = {});
470474
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
471475
Environment* env,
472476
const char* main_script_source_utf8,
473-
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
477+
std::unique_ptr<InspectorParentHandle> ignored_donotuse_removeme = {});
474478
NODE_EXTERN void FreeEnvironment(Environment* env);
475479

476480
// Set a callback that is called when process.exit() is called from JS,

src/node_worker.cc

+3-6
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ void Worker::Run() {
310310
std::move(argv_),
311311
std::move(exec_argv_),
312312
EnvironmentFlags::kNoFlags,
313-
thread_id_));
313+
thread_id_,
314+
std::move(inspector_parent_handle_)));
314315
if (is_stopped()) return;
315316
CHECK_NOT_NULL(env_);
316317
env_->set_env_vars(std::move(env_vars_));
@@ -328,12 +329,8 @@ void Worker::Run() {
328329
{
329330
CreateEnvMessagePort(env_.get());
330331
Debug(this, "Created message port for worker %llu", thread_id_.id);
331-
if (LoadEnvironment(env_.get(),
332-
StartExecutionCallback{},
333-
std::move(inspector_parent_handle_))
334-
.IsEmpty()) {
332+
if (LoadEnvironment(env_.get(), StartExecutionCallback{}).IsEmpty())
335333
return;
336-
}
337334

338335
Debug(this, "Loaded environment for worker %llu", thread_id_.id);
339336
}

test/cctest/node_test_fixture.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ class EnvironmentTestFixture : public NodeTestFixture {
135135
public:
136136
class Env {
137137
public:
138-
Env(const v8::HandleScope& handle_scope, const Argv& argv) {
138+
Env(const v8::HandleScope& handle_scope,
139+
const Argv& argv,
140+
node::EnvironmentFlags::Flags flags =
141+
node::EnvironmentFlags::kDefaultFlags) {
139142
auto isolate = handle_scope.GetIsolate();
140143
context_ = node::NewContext(isolate);
141144
CHECK(!context_.IsEmpty());
@@ -145,10 +148,13 @@ class EnvironmentTestFixture : public NodeTestFixture {
145148
&NodeTestFixture::current_loop,
146149
platform.get());
147150
CHECK_NE(nullptr, isolate_data_);
151+
std::vector<std::string> args(*argv, *argv + 1);
152+
std::vector<std::string> exec_args(*argv, *argv + 1);
148153
environment_ = node::CreateEnvironment(isolate_data_,
149154
context_,
150-
1, *argv,
151-
argv.nr_args(), *argv);
155+
args,
156+
exec_args,
157+
flags);
152158
CHECK_NE(nullptr, environment_);
153159
}
154160

test/cctest/test_environment.cc

+6-5
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,9 @@ TEST_F(EnvironmentTest, AtExitRunsJS) {
168168
TEST_F(EnvironmentTest, MultipleEnvironmentsPerIsolate) {
169169
const v8::HandleScope handle_scope(isolate_);
170170
const Argv argv;
171+
// Only one of the Environments can have default flags and own the inspector.
171172
Env env1 {handle_scope, argv};
172-
Env env2 {handle_scope, argv};
173+
Env env2 {handle_scope, argv, node::EnvironmentFlags::kNoFlags};
173174

174175
AtExit(*env1, at_exit_callback1);
175176
AtExit(*env2, at_exit_callback2);
@@ -334,7 +335,7 @@ TEST_F(EnvironmentTest, InspectorMultipleEmbeddedEnvironments) {
334335
" id: 1,\n"
335336
" method: 'Runtime.evaluate',\n"
336337
" params: {\n"
337-
" expression: 'global.variableFromParent = 42;'\n"
338+
" expression: 'globalThis.variableFromParent = 42;'\n"
338339
" }\n"
339340
" })\n"
340341
" });\n"
@@ -401,14 +402,14 @@ TEST_F(EnvironmentTest, InspectorMultipleEmbeddedEnvironments) {
401402
{ "dummy" },
402403
{},
403404
node::EnvironmentFlags::kNoFlags,
404-
data->thread_id);
405+
data->thread_id,
406+
std::move(data->inspector_parent_handle));
405407
CHECK_NOT_NULL(environment);
406408

407409
v8::Local<v8::Value> extracted_value = LoadEnvironment(
408410
environment,
409411
"while (!global.variableFromParent) {}\n"
410-
"return global.variableFromParent;",
411-
std::move(data->inspector_parent_handle)).ToLocalChecked();
412+
"return global.variableFromParent;").ToLocalChecked();
412413

413414
uv_run(&loop, UV_RUN_DEFAULT);
414415
CHECK(extracted_value->IsInt32());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
// Regression test for https://github.com./nodejs/node/issues/32648
5+
6+
common.skipIfInspectorDisabled();
7+
8+
const { NodeInstance } = require('../common/inspector-helper.js');
9+
10+
async function runTest() {
11+
const child = new NodeInstance(['--inspect-brk-node=0', '-p', '42']);
12+
const session = await child.connectInspectorSession();
13+
await session.send({ method: 'Runtime.enable' });
14+
await session.send({ method: 'Debugger.enable' });
15+
await session.send({ method: 'Runtime.runIfWaitingForDebugger' });
16+
await session.waitForNotification((notification) => {
17+
// The main assertion here is that we do hit the loader script first.
18+
return notification.method === 'Debugger.scriptParsed' &&
19+
notification.params.url === 'internal/bootstrap/loaders.js';
20+
});
21+
22+
await session.waitForNotification('Debugger.paused');
23+
await session.send({ method: 'Debugger.resume' });
24+
await session.waitForNotification('Debugger.paused');
25+
await session.runToCompletion();
26+
}
27+
28+
runTest().then(common.mustCall());

0 commit comments

Comments
 (0)