diff options
author | Ron Yorston <rmy@pobox.com> | 2024-06-22 10:40:16 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-06-22 12:26:19 +0100 |
commit | 790e37727319c3dd9c2d4e45dac9b6cc38a5d25f (patch) | |
tree | b375a322562dd6691b7eaf139d2b7b844b31ccb9 | |
parent | 91226ced0a04302dfe04227aff062cade476a930 (diff) | |
download | busybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.tar.gz busybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.tar.bz2 busybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.zip |
win32: revert 'don't set error mode'
Commit eb376b5d1 (win32: don't set error mode) removed a call to
SetErrorMode(SEM_FAILCRITICALERRORS).
But the documentation says:
Best practice is that all applications call the process-wide
SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS
at startup. This is to prevent error mode dialogs from hanging
the application.
Doing this prevents the system from displaying useful information,
though. The application should attempt to tell the user what went
wrong.
Reinstate the call to SetErrorMode() and try to provide an error
message, at least for the situation mentioned in issue #423 and
other similar cases.
Adds 360-368 bytes.
(GitHub issue #423)
-rw-r--r-- | libbb/appletlib.c | 4 | ||||
-rw-r--r-- | win32/process.c | 93 |
2 files changed, 68 insertions, 29 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 51824f1b3..c90285ae9 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -1349,6 +1349,10 @@ int main(int argc UNUSED_PARAM, char **argv) | |||
1349 | break; | 1349 | break; |
1350 | } | 1350 | } |
1351 | } | 1351 | } |
1352 | |||
1353 | /* Have this process handle critical errors itself: the default | ||
1354 | * system-generated error dialogs may be inconvenient. */ | ||
1355 | SetErrorMode(SEM_FAILCRITICALERRORS); | ||
1352 | #endif | 1356 | #endif |
1353 | 1357 | ||
1354 | #if defined(__MINGW64_VERSION_MAJOR) | 1358 | #if defined(__MINGW64_VERSION_MAJOR) |
diff --git a/win32/process.c b/win32/process.c index caea87492..94a1e23a9 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -443,7 +443,65 @@ BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType) | |||
443 | return FALSE; | 443 | return FALSE; |
444 | } | 444 | } |
445 | 445 | ||
446 | static NORETURN void wait_for_child(HANDLE child) | 446 | static int exit_code_to_wait_status_cmd(DWORD exit_code, const char *cmd) |
447 | { | ||
448 | int sig, status; | ||
449 | DECLARE_PROC_ADDR(ULONG, RtlNtStatusToDosError, NTSTATUS); | ||
450 | DWORD flags, code; | ||
451 | char *msg = NULL; | ||
452 | |||
453 | if (exit_code == 0xc0000005) | ||
454 | return SIGSEGV; | ||
455 | else if (exit_code == 0xc000013a) | ||
456 | return SIGINT; | ||
457 | |||
458 | // When a process is terminated as if by a signal the Windows | ||
459 | // exit code is zero apart from the signal in its topmost byte. | ||
460 | // This is a busybox-w32 convention. | ||
461 | sig = exit_code >> 24; | ||
462 | if (sig != 0 && exit_code == sig << 24 && is_valid_signal(sig)) | ||
463 | return sig; | ||
464 | |||
465 | // The exit code may be an NTSTATUS code. Try to obtain a | ||
466 | // descriptive message for it. | ||
467 | if (exit_code > 0xff) { | ||
468 | flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM; | ||
469 | if (INIT_PROC_ADDR(ntdll.dll, RtlNtStatusToDosError)) { | ||
470 | code = RtlNtStatusToDosError(exit_code); | ||
471 | if (FormatMessage(flags, NULL, code, 0, (char *)&msg, 0, NULL)) { | ||
472 | char *cr = strrchr(msg, '\r'); | ||
473 | if (cr) { // Replace CRLF with a space | ||
474 | cr[0] = ' '; | ||
475 | cr[1] = '\0'; | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | if (cmd) | ||
481 | bb_error_msg("%s: %sError 0x%lx", cmd, msg ?: "", exit_code); | ||
482 | else | ||
483 | bb_error_msg("%s: %sError 0x%lx" + 4, msg ?: "", exit_code); | ||
484 | LocalFree(msg); | ||
485 | } | ||
486 | |||
487 | // Use least significant byte as exit code, but not if it's zero | ||
488 | // and the Windows exit code as a whole is non-zero. | ||
489 | status = exit_code & 0xff; | ||
490 | if (exit_code != 0 && status == 0) | ||
491 | status = 255; | ||
492 | return status << 8; | ||
493 | } | ||
494 | |||
495 | static int exit_code_to_posix_cmd(DWORD exit_code, const char *cmd) | ||
496 | { | ||
497 | int status = exit_code_to_wait_status_cmd(exit_code, cmd); | ||
498 | |||
499 | if (WIFSIGNALED(status)) | ||
500 | return 128 + WTERMSIG(status); | ||
501 | return WEXITSTATUS(status); | ||
502 | } | ||
503 | |||
504 | static NORETURN void wait_for_child(HANDLE child, const char *cmd) | ||
447 | { | 505 | { |
448 | DWORD code; | 506 | DWORD code; |
449 | 507 | ||
@@ -451,7 +509,7 @@ static NORETURN void wait_for_child(HANDLE child) | |||
451 | SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE); | 509 | SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE); |
452 | WaitForSingleObject(child, INFINITE); | 510 | WaitForSingleObject(child, INFINITE); |
453 | GetExitCodeProcess(child, &code); | 511 | GetExitCodeProcess(child, &code); |
454 | exit(exit_code_to_posix(code)); | 512 | exit(exit_code_to_posix_cmd(code, cmd)); |
455 | } | 513 | } |
456 | 514 | ||
457 | int | 515 | int |
@@ -459,7 +517,7 @@ mingw_execvp(const char *cmd, char *const *argv) | |||
459 | { | 517 | { |
460 | intptr_t ret = mingw_spawnvp(P_NOWAIT, cmd, argv); | 518 | intptr_t ret = mingw_spawnvp(P_NOWAIT, cmd, argv); |
461 | if (ret != -1) | 519 | if (ret != -1) |
462 | wait_for_child((HANDLE)ret); | 520 | wait_for_child((HANDLE)ret, cmd); |
463 | return ret; | 521 | return ret; |
464 | } | 522 | } |
465 | 523 | ||
@@ -468,7 +526,7 @@ mingw_execve(const char *cmd, char *const *argv, char *const *envp) | |||
468 | { | 526 | { |
469 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); | 527 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); |
470 | if (ret != -1) | 528 | if (ret != -1) |
471 | wait_for_child((HANDLE)ret); | 529 | wait_for_child((HANDLE)ret, cmd); |
472 | return ret; | 530 | return ret; |
473 | } | 531 | } |
474 | 532 | ||
@@ -896,33 +954,10 @@ int FAST_FUNC is_valid_signal(int number) | |||
896 | 954 | ||
897 | int exit_code_to_wait_status(DWORD exit_code) | 955 | int exit_code_to_wait_status(DWORD exit_code) |
898 | { | 956 | { |
899 | int sig, status; | 957 | return exit_code_to_wait_status_cmd(exit_code, NULL); |
900 | |||
901 | if (exit_code == 0xc0000005) | ||
902 | return SIGSEGV; | ||
903 | else if (exit_code == 0xc000013a) | ||
904 | return SIGINT; | ||
905 | |||
906 | // When a process is terminated as if by a signal the Windows | ||
907 | // exit code is zero apart from the signal in its topmost byte. | ||
908 | // This is a busybox-w32 convention. | ||
909 | sig = exit_code >> 24; | ||
910 | if (sig != 0 && exit_code == sig << 24 && is_valid_signal(sig)) | ||
911 | return sig; | ||
912 | |||
913 | // Use least significant byte as exit code, but not if it's zero | ||
914 | // and the Windows exit code as a whole is non-zero. | ||
915 | status = exit_code & 0xff; | ||
916 | if (exit_code != 0 && status == 0) | ||
917 | status = 255; | ||
918 | return status << 8; | ||
919 | } | 958 | } |
920 | 959 | ||
921 | int exit_code_to_posix(DWORD exit_code) | 960 | int exit_code_to_posix(DWORD exit_code) |
922 | { | 961 | { |
923 | int status = exit_code_to_wait_status(exit_code); | 962 | return exit_code_to_posix_cmd(exit_code, NULL); |
924 | |||
925 | if (WIFSIGNALED(status)) | ||
926 | return 128 + WTERMSIG(status); | ||
927 | return WEXITSTATUS(status); | ||
928 | } | 963 | } |