Skip to content

Add error dialog for critical errors on Windows #54836

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

Open
wants to merge 2 commits into
base: ct/more-fprint
Choose a base branch
from

Conversation

topolarity
Copy link
Member

@topolarity topolarity commented Jun 17, 2024

This change adds a small dialog for fatal errors on Windows:

with a corresponding entry in the Application log (in Event Viewer)

This is intended primarily for users of PackageCompiler.jl, who might be using Julia in a GUI application.

If a Julia-compiled library fails in a GUI application, users currently they have no good way to know why/how their application crashed if, e.g., an exception was accidentally left unhandled in their Julia code.

Depends on #54835

TODO: Should this be a jl_options flag to determine whether to show the GUI? Should we log to the event log unconditionally? Is there any way that we can automatically detect whether stderr is connected to a terminal and user-visible?

@giordano giordano added system:windows Affects only Windows error handling Handling of exceptions by Julia or the user labels Jun 17, 2024
This can be very useful when your Julia-built library hits an unexpected
exception and causes a GUI-based application to crash with no error
message.
event_source, EVENTLOG_ERROR_TYPE, /* category */ 0, /* event_id */ (DWORD)0xE0000000L,
/* user_sid */ NULL, /* n_strings */ 1, /* data_size */ 0, strings, /* data */ NULL
);
MessageBoxW(NULL, /* message */ L"error: libjulia received a fatal signal.\n\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know very little about Windows, so my apologies if these questions are dumb, but: 1. Is this call async, or does it block?
2. Is this really safe to call here? In particular,
3. I am slightly worried about situations I experienced in an entirely different context were broadly similar code could lead to hundreds of dialog boxes spamming a user (when code that launched a ton of subprocesses to process data had them all fail simultaneously -- e.g. because a network connection dropped).

Anyway, none of this is meant as argument against this PR (which to me, as a non-Windows user, seems quite useful). Feel free to ignore me :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On 1: it blocks the thread.

@davidanthoff
Copy link
Contributor

Probably also needs to detect scenarios where no windows desktop is present? SSH, PowerShell remoting, running as a service etc.

Somehow making the dialog box optional seems like a good idea to me.

@@ -278,59 +298,88 @@ LONG WINAPI jl_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
break;
}
}
ios_t full_error, summary;
ios_mem(&full_error, 1024);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling malloc unconditionally here is a bit wasteful, since we will call it on demand when actually needed

Suggested change
ios_mem(&full_error, 1024);
ios_mem(&full_error, 0);

Comment on lines +993 to +1005
/* Fast-path empty strings, as MultiByteToWideChar() returns zero for them. */
if (str[0] == '\0') {
wchar_t *wstr = (wchar_t *)malloc(sizeof(wchar_t));
wstr[0] = L'\0';
return wstr;
}
size_t len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (!len)
return NULL;
wchar_t *wstr = (wchar_t *)malloc(len * sizeof(wchar_t));
if (!wstr || !MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len))
return NULL;
return wstr;
Copy link
Member

@vtjnash vtjnash Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* Fast-path empty strings, as MultiByteToWideChar() returns zero for them. */
if (str[0] == '\0') {
wchar_t *wstr = (wchar_t *)malloc(sizeof(wchar_t));
wstr[0] = L'\0';
return wstr;
}
size_t len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (!len)
return NULL;
wchar_t *wstr = (wchar_t *)malloc(len * sizeof(wchar_t));
if (!wstr || !MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len))
return NULL;
return wstr;
ssize_t wlen = uv_wtf8_length_as_utf16(str);
wchar_t *wstr = (wchar_t *)malloc_s(sizeof(wchar_t) * wlen);
uv_wtf8_to_utf16(str, wstr, wlen);
return wstr;

This is a more reliable (and concise) version of MultiByteToWideChar now provided by libuv

if (event_source != INVALID_HANDLE_VALUE) {
ios_putc('\0', &full_error);
const wchar_t *strings[] = {
ios_utf8_to_wchar(full_error.buf),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should free this

Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, I think this should work okay

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error handling Handling of exceptions by Julia or the user system:windows Affects only Windows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants