Skip to content

Commit b75ca50

Browse files
Eugene Ostroukhovcjihrig
Eugene Ostroukhov
authored andcommitted
inspector: Do not crash if the port is n/a
Node process will no longer terminate with an assertion if the inspector port is not available. PR-URL: #7874 Reviewed-By: bnoordhuis - Ben Noordhuis <[email protected]> Reviewed-By: jasnell - James M Snell <[email protected]> Conflicts: src/node.cc
1 parent 96d15e2 commit b75ca50

File tree

4 files changed

+55
-47
lines changed

4 files changed

+55
-47
lines changed

doc/api/process.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,8 +1660,9 @@ cases:
16601660
source code internal in Node.js's bootstrapping process threw an error
16611661
when the bootstrapping function was called. This is extremely rare,
16621662
and generally can only happen during development of Node.js itself.
1663-
* `12` **Invalid Debug Argument** - The `--debug` and/or `--debug-brk`
1664-
options were set, but an invalid port number was chosen.
1663+
* `12` **Invalid Debug Argument** - The `--debug`, `--inspect` and/or
1664+
`--debug-brk` options were set, but the port number chosen was invalid
1665+
or unavailable.
16651666
* `>128` **Signal Exits** - If Node.js receives a fatal signal such as
16661667
`SIGKILL` or `SIGHUP`, then its exit code will be `128` plus the
16671668
value of the signal code. This is a standard Unix practice, since

src/inspector_agent.cc

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,17 @@ class AgentImpl {
164164
~AgentImpl();
165165

166166
// Start the inspector agent thread
167-
void Start(v8::Platform* platform, int port, bool wait);
167+
bool Start(v8::Platform* platform, int port, bool wait);
168168
// Stop the inspector agent
169169
void Stop();
170170

171171
bool IsStarted();
172-
bool IsConnected() { return connected_; }
172+
bool IsConnected() { return state_ == State::kConnected; }
173173
void WaitForDisconnect();
174174

175175
private:
176176
using MessageQueue = std::vector<std::pair<int, String16>>;
177+
enum class State { kNew, kAccepting, kConnected, kDone, kError };
177178

178179
static void ThreadCbIO(void* agent);
179180
static void OnSocketConnectionIO(uv_stream_t* server, int status);
@@ -194,6 +195,7 @@ class AgentImpl {
194195
const String16& message);
195196
void SwapBehindLock(MessageQueue* vector1, MessageQueue* vector2);
196197
void PostIncomingMessage(const String16& message);
198+
State ToState(State state);
197199

198200
uv_sem_t start_sem_;
199201
ConditionVariable pause_cond_;
@@ -204,8 +206,8 @@ class AgentImpl {
204206

205207
int port_;
206208
bool wait_;
207-
bool connected_;
208209
bool shutting_down_;
210+
State state_;
209211
node::Environment* parent_env_;
210212

211213
uv_async_t data_written_;
@@ -313,8 +315,8 @@ class V8NodeInspector : public blink::V8Inspector {
313315

314316
AgentImpl::AgentImpl(Environment* env) : port_(0),
315317
wait_(false),
316-
connected_(false),
317318
shutting_down_(false),
319+
state_(State::kNew),
318320
parent_env_(env),
319321
client_socket_(nullptr),
320322
inspector_(nullptr),
@@ -333,17 +335,11 @@ AgentImpl::~AgentImpl() {
333335
uv_close(reinterpret_cast<uv_handle_t*>(&data_written_), nullptr);
334336
}
335337

336-
void AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
338+
bool AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
337339
auto env = parent_env_;
338340
inspector_ = new V8NodeInspector(this, env, platform);
339-
340-
int err;
341-
342341
platform_ = platform;
343-
344-
err = uv_loop_init(&child_loop_);
345-
CHECK_EQ(err, 0);
346-
err = uv_async_init(env->event_loop(), &data_written_, nullptr);
342+
int err = uv_async_init(env->event_loop(), &data_written_, nullptr);
347343
CHECK_EQ(err, 0);
348344

349345
uv_unref(reinterpret_cast<uv_handle_t*>(&data_written_));
@@ -355,21 +351,20 @@ void AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
355351
CHECK_EQ(err, 0);
356352
uv_sem_wait(&start_sem_);
357353

354+
if (state_ == State::kError) {
355+
Stop();
356+
return false;
357+
}
358+
state_ = State::kAccepting;
358359
if (wait) {
359360
DispatchMessages();
360361
}
362+
return true;
361363
}
362364

363365
void AgentImpl::Stop() {
364-
// TODO(repenaxa): hop on the right thread.
365-
DisconnectAndDisposeIO(client_socket_);
366366
int err = uv_thread_join(&thread_);
367367
CHECK_EQ(err, 0);
368-
369-
uv_run(&child_loop_, UV_RUN_NOWAIT);
370-
371-
err = uv_loop_close(&child_loop_);
372-
CHECK_EQ(err, 0);
373368
delete inspector_;
374369
}
375370

@@ -428,7 +423,6 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket,
428423
Mutex::ScopedLock scoped_lock(pause_lock_);
429424
if (read > 0) {
430425
String16 str = String16::fromUTF8(buf->base, read);
431-
PostIncomingMessage(str);
432426
// TODO(pfeldman): Instead of blocking execution while debugger
433427
// engages, node should wait for the run callback from the remote client
434428
// and initiate its startup. This is a change to node.cc that should be
@@ -437,11 +431,7 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket,
437431
wait_ = false;
438432
uv_sem_post(&start_sem_);
439433
}
440-
441-
platform_->CallOnForegroundThread(parent_env_->isolate(),
442-
new DispatchOnInspectorBackendTask(this));
443-
parent_env_->isolate()->RequestInterrupt(InterruptCallback, this);
444-
uv_async_send(&data_written_);
434+
PostIncomingMessage(str);
445435
} else if (read <= 0) {
446436
// EOF
447437
if (client_socket_ == socket) {
@@ -476,8 +466,10 @@ void AgentImpl::WriteCbIO(uv_async_t* async) {
476466
void AgentImpl::WorkerRunIO() {
477467
sockaddr_in addr;
478468
uv_tcp_t server;
479-
int err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);
480-
CHECK_EQ(0, err);
469+
int err = uv_loop_init(&child_loop_);
470+
CHECK_EQ(err, 0);
471+
err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);
472+
CHECK_EQ(err, 0);
481473
io_thread_req_.data = this;
482474
uv_tcp_init(&child_loop_, &server);
483475
uv_ip4_addr("0.0.0.0", port_, &addr);
@@ -488,19 +480,26 @@ void AgentImpl::WorkerRunIO() {
488480
err = uv_listen(reinterpret_cast<uv_stream_t*>(&server), 1,
489481
OnSocketConnectionIO);
490482
}
491-
if (err == 0) {
492-
PrintDebuggerReadyMessage(port_);
493-
} else {
483+
if (err != 0) {
494484
fprintf(stderr, "Unable to open devtools socket: %s\n", uv_strerror(err));
495-
ABORT();
485+
state_ = State::kError; // Safe, main thread is waiting on semaphore
486+
uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);
487+
uv_close(reinterpret_cast<uv_handle_t*>(&server), nullptr);
488+
uv_loop_close(&child_loop_);
489+
uv_sem_post(&start_sem_);
490+
return;
496491
}
492+
PrintDebuggerReadyMessage(port_);
497493
if (!wait_) {
498494
uv_sem_post(&start_sem_);
499495
}
500496
uv_run(&child_loop_, UV_RUN_DEFAULT);
501497
uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);
502498
uv_close(reinterpret_cast<uv_handle_t*>(&server), nullptr);
503-
uv_run(&child_loop_, UV_RUN_DEFAULT);
499+
DisconnectAndDisposeIO(client_socket_);
500+
uv_run(&child_loop_, UV_RUN_NOWAIT);
501+
err = uv_loop_close(&child_loop_);
502+
CHECK_EQ(err, 0);
504503
}
505504

506505
void AgentImpl::AppendMessage(MessageQueue* queue, int session_id,
@@ -543,16 +542,19 @@ void AgentImpl::DispatchMessages() {
543542
for (const MessageQueue::value_type& pair : tasks) {
544543
const String16& message = pair.second;
545544
if (message == TAG_CONNECT) {
546-
CHECK_EQ(false, connected_);
545+
CHECK_EQ(State::kAccepting, state_);
547546
backend_session_id_++;
548-
connected_ = true;
547+
state_ = State::kConnected;
549548
fprintf(stderr, "Debugger attached.\n");
550549
inspector_->connectFrontend(new ChannelImpl(this));
551550
} else if (message == TAG_DISCONNECT) {
552-
CHECK(connected_);
553-
connected_ = false;
554-
if (!shutting_down_)
551+
CHECK_EQ(State::kConnected, state_);
552+
if (shutting_down_) {
553+
state_ = State::kDone;
554+
} else {
555555
PrintDebuggerReadyMessage(port_);
556+
state_ = State::kAccepting;
557+
}
556558
inspector_->quitMessageLoopOnPause();
557559
inspector_->disconnectFrontend();
558560
} else {
@@ -576,8 +578,8 @@ Agent::~Agent() {
576578
delete impl;
577579
}
578580

579-
void Agent::Start(v8::Platform* platform, int port, bool wait) {
580-
impl->Start(platform, port, wait);
581+
bool Agent::Start(v8::Platform* platform, int port, bool wait) {
582+
return impl->Start(platform, port, wait);
581583
}
582584

583585
void Agent::Stop() {

src/inspector_agent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Agent {
2525
~Agent();
2626

2727
// Start the inspector agent thread
28-
void Start(v8::Platform* platform, int port, bool wait);
28+
bool Start(v8::Platform* platform, int port, bool wait);
2929
// Stop the inspector agent
3030
void Stop();
3131

src/node.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,11 @@ static struct {
208208
platform_ = nullptr;
209209
}
210210

211-
void StartInspector(Environment *env, int port, bool wait) {
211+
bool StartInspector(Environment *env, int port, bool wait) {
212212
#if HAVE_INSPECTOR
213-
env->inspector_agent()->Start(platform_, port, wait);
213+
return env->inspector_agent()->Start(platform_, port, wait);
214+
#else
215+
return true;
214216
#endif // HAVE_INSPECTOR
215217
}
216218

@@ -3836,8 +3838,7 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) {
38363838
static void StartDebug(Environment* env, bool wait) {
38373839
CHECK(!debugger_running);
38383840
if (use_inspector) {
3839-
v8_platform.StartInspector(env, inspector_port, wait);
3840-
debugger_running = true;
3841+
debugger_running = v8_platform.StartInspector(env, inspector_port, wait);
38413842
} else {
38423843
env->debugger_agent()->set_dispatch_handler(
38433844
DispatchMessagesDebugAgentCallback);
@@ -4547,8 +4548,12 @@ static void StartNodeInstance(void* arg) {
45474548
ShouldAbortOnUncaughtException);
45484549

45494550
// Start debug agent when argv has --debug
4550-
if (instance_data->use_debug_agent())
4551+
if (instance_data->use_debug_agent()) {
45514552
StartDebug(env, debug_wait_connect);
4553+
if (use_inspector && !debugger_running) {
4554+
exit(12);
4555+
}
4556+
}
45524557

45534558
{
45544559
Environment::AsyncCallbackScope callback_scope(env);

0 commit comments

Comments
 (0)