-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Proposal
We propose to make the Dart VM stop automatically restoring the terminal settings upon exit. A proposed implementation is at https://dart-review.googlesource.com/c/sdk/+/190484.
Programs that set Stdin.echoMode or Stdin.lineMode must now manually restore the terminal settings upon exit if they wish.
Rationale
The automatic terminal setting restoration happens unconditionally and can lead to undesirable behavior e.g. when the program does not care about terminal settings and is sharing a process group with a program that does care. E.g. if dart's output is piped into less(1), then there is a race condition where dart might see the raw terminal settings set by less(1), and if the dart VM exits after less(1) has exited, then it will restore the raw terminal settings, leaving the user with a seemingly defective shell with echo disabled. This race condition can be reproduced using:
cat > yes.dart << EOF
main() {
for (int i = 0; i < 1000000; i++) {
print("yes");
}
}
EOF
stty; (sleep 1 && dart yes.dart) | less; stty; stty sane
The user will end up with a shell with echo behavior disabled. The stty command shows the current terminal settings, where the difference can be seen, and stty sane fixes the settings before returning to the shell prompt. The stty sane call can be omitted to see the defective shell prompt.
dart:io already provides all the functionality for programs to correctly implement the restoration behavior themselves. This class of terminal setting corruption bugs are eliminated by shifting the burden onto the programs that use interactive input and change these settings. This design matches that of other programming languages.
Impact
Affected programs won't break for the duration of their run, although the terminal state settings for line mode and echo mode may be unexpected afterwards, especially if the program is terminated by a signal or an unhandled exception. Users of POSIX systems can manually repair their terminal session by running stty echo echonl icanon or stty sane.
Mitigation
Programs that change the Stdin settings lineMode and echoMode are now responsible for restoring the settings upon program exit. E.g. a program disabling echoMode will now need to restore the setting itself and handle exiting by the appropriate signals if desired:
import 'dart:io';
import 'dart:async';
main() {
bool echoWasEnabled = stdin.echoMode;
try {
late StreamSubscription subscription;
subscription = ProcessSignal.sigint.watch().listen((ProcessSignal signal) {
stdin.echoMode = echoWasEnabled;
subscription.cancel();
Process.killPid(pid, signal); /* Die by the signal. */
});
stdin.echoMode = false;
} finally {
stdin.echoMode = echoWasEnabled;
}
}