Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b5dda32

Browse filesBrowse files
bnoordhuisBridgeAR
authored andcommitted
src: restore stdio on program exit
Record the state of the stdio file descriptors on start-up and restore them to that state on exit. This should prevent issues where node.js sometimes leaves stdio in raw or non-blocking mode. This is a reworked version of commit c2c9c0c from May 2018 that was reverted in commit 14dc17d from June 2018. The revert was a little light on details but I infer that the problem was caused by a missing call to `uv_tty_reset_mode()`. Apropos the NOLINT comments: cpplint doesn't understand do/while statements, it thinks they're while statements without a body. Fixes: #14752 Fixes: #21020 Original-PR-URL: #20592 PR-URL: #24260 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent abe5d05 commit b5dda32
Copy full SHA for b5dda32

File tree

Expand file treeCollapse file tree

4 files changed

+90
-7
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+90
-7
lines changed
Open diff view settings
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+87-5Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
#else
9898
#include <pthread.h>
9999
#include <sys/resource.h> // getrlimit, setrlimit
100+
#include <termios.h> // tcgetattr, tcsetattr
100101
#include <unistd.h> // STDIN_FILENO, STDERR_FILENO
101102
#endif
102103

@@ -182,7 +183,7 @@ void WaitForInspectorDisconnect(Environment* env) {
182183
}
183184

184185
void SignalExit(int signo) {
185-
uv_tty_reset_mode();
186+
ResetStdio();
186187
#ifdef __FreeBSD__
187188
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
188189
struct sigaction sa;
@@ -490,6 +491,16 @@ void RegisterSignalHandler(int signal,
490491

491492
#endif // __POSIX__
492493

494+
#ifdef __POSIX__
495+
static struct {
496+
int flags;
497+
bool isatty;
498+
struct stat stat;
499+
struct termios termios;
500+
} stdio[1 + STDERR_FILENO];
501+
#endif // __POSIX__
502+
503+
493504
inline void PlatformInit() {
494505
#ifdef __POSIX__
495506
#if HAVE_INSPECTOR
@@ -500,16 +511,18 @@ inline void PlatformInit() {
500511
#endif // HAVE_INSPECTOR
501512

502513
// Make sure file descriptors 0-2 are valid before we start logging anything.
503-
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
504-
struct stat ignored;
505-
if (fstat(fd, &ignored) == 0)
514+
for (auto& s : stdio) {
515+
const int fd = &s - stdio;
516+
if (fstat(fd, &s.stat) == 0)
506517
continue;
507518
// Anything but EBADF means something is seriously wrong. We don't
508519
// have to special-case EINTR, fstat() is not interruptible.
509520
if (errno != EBADF)
510521
ABORT();
511522
if (fd != open("/dev/null", O_RDWR))
512523
ABORT();
524+
if (fstat(fd, &s.stat) != 0)
525+
ABORT();
513526
}
514527

515528
#if HAVE_INSPECTOR
@@ -532,6 +545,27 @@ inline void PlatformInit() {
532545
}
533546
#endif // !NODE_SHARED_MODE
534547

548+
// Record the state of the stdio file descriptors so we can restore it
549+
// on exit. Needs to happen before installing signal handlers because
550+
// they make use of that information.
551+
for (auto& s : stdio) {
552+
const int fd = &s - stdio;
553+
int err;
554+
555+
do
556+
s.flags = fcntl(fd, F_GETFL);
557+
while (s.flags == -1 && errno == EINTR); // NOLINT
558+
CHECK_NE(s.flags, -1);
559+
560+
if (!isatty(fd)) continue;
561+
s.isatty = true;
562+
563+
do
564+
err = tcgetattr(fd, &s.termios);
565+
while (err == -1 && errno == EINTR); // NOLINT
566+
CHECK_EQ(err, 0);
567+
}
568+
535569
RegisterSignalHandler(SIGINT, SignalExit, true);
536570
RegisterSignalHandler(SIGTERM, SignalExit, true);
537571

@@ -571,6 +605,54 @@ inline void PlatformInit() {
571605
#endif // _WIN32
572606
}
573607

608+
609+
// Safe to call more than once and from signal handlers.
610+
void ResetStdio() {
611+
uv_tty_reset_mode();
612+
#ifdef __POSIX__
613+
for (auto& s : stdio) {
614+
const int fd = &s - stdio;
615+
616+
struct stat tmp;
617+
if (-1 == fstat(fd, &tmp)) {
618+
CHECK_EQ(errno, EBADF); // Program closed file descriptor.
619+
continue;
620+
}
621+
622+
bool is_same_file =
623+
(s.stat.st_dev == tmp.st_dev && s.stat.st_ino == tmp.st_ino);
624+
if (!is_same_file) continue; // Program reopened file descriptor.
625+
626+
int flags;
627+
do
628+
flags = fcntl(fd, F_GETFL);
629+
while (flags == -1 && errno == EINTR); // NOLINT
630+
CHECK_NE(flags, -1);
631+
632+
// Restore the O_NONBLOCK flag if it changed.
633+
if (O_NONBLOCK & (flags ^ s.flags)) {
634+
flags &= ~O_NONBLOCK;
635+
flags |= s.flags & O_NONBLOCK;
636+
637+
int err;
638+
do
639+
err = fcntl(fd, F_SETFL, flags);
640+
while (err == -1 && errno == EINTR); // NOLINT
641+
CHECK_NE(err, -1);
642+
}
643+
644+
if (s.isatty) {
645+
int err;
646+
do
647+
err = tcsetattr(fd, TCSANOW, &s.termios);
648+
while (err == -1 && errno == EINTR); // NOLINT
649+
CHECK_NE(err, -1);
650+
}
651+
}
652+
#endif // __POSIX__
653+
}
654+
655+
574656
int ProcessGlobalArgs(std::vector<std::string>* args,
575657
std::vector<std::string>* exec_args,
576658
std::vector<std::string>* errors,
@@ -826,7 +908,7 @@ void Init(int* argc,
826908
}
827909

828910
InitializationResult InitializeOncePerProcess(int argc, char** argv) {
829-
atexit([] () { uv_tty_reset_mode(); });
911+
atexit(ResetStdio);
830912
PlatformInit();
831913
per_process::node_start_time = uv_hrtime();
832914

Collapse file

‎src/node_errors.cc‎

Copy file name to clipboardExpand all lines: src/node_errors.cc
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ void AppendExceptionLine(Environment* env,
230230
Mutex::ScopedLock lock(per_process::tty_mutex);
231231
env->set_printed_error(true);
232232

233-
uv_tty_reset_mode();
233+
ResetStdio();
234234
PrintErrorString("\n%s", source.c_str());
235235
return;
236236
}
Collapse file

‎src/node_internals.h‎

Copy file name to clipboardExpand all lines: src/node_internals.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ void PrintCaughtException(v8::Isolate* isolate,
9191
const v8::TryCatch& try_catch);
9292

9393
void WaitForInspectorDisconnect(Environment* env);
94+
void ResetStdio(); // Safe to call more than once and from signal handlers.
9495
void SignalExit(int signo);
9596
#ifdef __POSIX__
9697
void RegisterSignalHandler(int signal,
Collapse file

‎src/node_main_instance.cc‎

Copy file name to clipboardExpand all lines: src/node_main_instance.cc
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ int NodeMainInstance::Run() {
145145

146146
env->set_can_call_into_js(false);
147147
env->stop_sub_worker_contexts();
148-
uv_tty_reset_mode();
148+
ResetStdio();
149149
env->RunCleanup();
150150
RunAtExit(env.get());
151151

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.