-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Console.Unix: also reset terminal state when process terminates due to an unhandled exception. #111272
Console.Unix: also reset terminal state when process terminates due to an unhandled exception. #111272
Conversation
…o an unhandled exception.
I manually checked the behavior with this program: if (args.Length > 0 && args[0] == "throw")
{
Console.ReadLine();
// Intentional crash
int[] arr = new int[1];
arr[100] = 10;
}
else
{
Process.Start(Environment.ProcessPath!, [ Assembly.GetExecutingAssembly().Location, "throw"]).WaitForExit();
} I don't think there's a good way to test this in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall the changes LGTM, but I would prefer @jkotas to sign of the part that registers for the AppDomain.CurrentDomain.UnhandledException event as I don't know all the pros and cons of doing so.
|
||
// InitializeTerminalAndSignalHandling will reset the terminal on a normal exit. | ||
// This also resets it for termination due to an unhandled exception. | ||
AppDomain.CurrentDomain.UnhandledException += delegate { Interop.Sys.UninitializeTerminal(); }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we should do that before the s_initialized
is set to true (so setting s_initialized
to true
is the last thing that is part of the initialization logic)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put it here intentionally because we won't start modifying the terminal until we've reached this point.
At this location we're sure to only add the delegate once.
I'm fine with moving it higher up, though this location should also be fine.
@adamsitnik can you confirm you'd still like me to move this higher up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't start modifying because there is a lock, but in theory once the flag is set to true some other thread can assume everything is initialized and it can be used.
runtime/src/libraries/System.Console/src/System/ConsolePal.Unix.cs
Lines 868 to 874 in 5abf582
internal static void EnsureConsoleInitialized() | |
{ | |
if (!s_initialized) | |
{ | |
EnsureInitializedCore(); // factored out for inlinability | |
} | |
} |
I just like to have all initialization flags set to true when all the initialization logic is finished. I won't block the PR without it, but I think that in the future somebody can add some new initialization logic after your new logic and then we are going to be in trouble if we miss that in a code review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
theory once the flag is set to true some other thread can assume everything is initialized and it can be used.
Does it mean that registering after s_initialized
is set increases chances that the app will terminate without resetting the terminal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean that registering after
s_initialized
is set increases chances that the app will terminate without resetting the terminal?
Based on the logic for AppDomain.CurrentDomain
I believe it's possible to be so (it seems to be non-trivial and can take some time, so in meantime something can use the console and then somehow crash the app).
runtime/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Lines 31 to 43 in 5abf582
public static AppDomain CurrentDomain | |
{ | |
get | |
{ | |
// Create AppDomain instance only once external code asks for it. AppDomain brings lots of unnecessary | |
// dependencies into minimal trimmed app via ToString method. | |
if (s_domain == null) | |
{ | |
Interlocked.CompareExchange(ref s_domain, new AppDomain(), null); | |
} | |
return s_domain; | |
} | |
} |
But the chances are very low.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW this comment made me realize that simplest "Hello World" app size after trimming may grow with this change. I am still not against it, just something to keep in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the chances are very low.
I agree that the chances are low, but this ordering is needlessly increasing them.
simplest "Hello World" app size after trimming may grow with this change
This is true for a lot of PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is true for a lot of PRs.
I know, but in case of Hello World there are some benchmarks that some people look at when comparing tech stacks. I just wanted to point it out since IIRC we may be having some automation that tracks such regressions. So then the person looking at it will find my comment and close it as "by design".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fyi, I explored what the implementation would need to implement it in a native signal handler. The challenge is that runtime will reset to the default SIGABRT handler (in PROCAbort
by calling SEHCleanupSignals
) and a handler that was added later for Console
that chains back to the runtime handler is not called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tmds big thanks for explaining why we have not relied on SIGABRT!
LGTM modulo feedback |
...braries/Common/src/Interop/Unix/System.Native/Interop.InitializeTerminalAndSignalHandling.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you for your help @tmds !
/ba-g the timeout in the Windows job is unrelated |
Fixes #110502.
@adamsitnik @jkotas ptal.