[Rd] Making use of win32_segv
Ivan Krylov
|kry|ov @end|ng |rom d|@root@org
Sun Jun 30 15:19:47 CEST 2024
Hello R-devel,
When checking packages on Windows, a crash of the process looks like a
sudden stop in the output of the child process, which can be very
perplexing for package maintainers (e.g. [1,2]), especially if the
stars are only right on Win-Builder but not on the maintainer's PC.
On Unix-like systems, we get a loud message from the SIGSEGV handler
and (if we're lucky and the memory manager is still mostly intact) an
R-level traceback. A similar signal handler, win32_segv(), is defined
in src/main.c for use on Windows, but I am not seeing a way it could be
called in the current codebase. The file src/gnuwin32/psignal.c that's
responsible for signals on Windows handles Ctrl+C but does not emit
SIGSEGV or SIGILL. Can we make use of vectored exception handling [3]
to globally catch unhandled exceptions in the Win32 process and
transform them into raise(SIGSEGV)?
One potential source of problems is threading. The normal Unix-like
sigactionSegv(...) doesn't care; if a non-main thread causes a crash
with SIGSEGV unblocked, it will run in that thread's context and call R
API from there. On Windows, where a simple REprintf() may go into a GUI
window, the crash handler may be written in a more cautious manner:
- Only set up the crash handler in Rterm, because this is mostly for
the benefit of the people reading the R CMD check output
- Compare GetCurrentThreadId() against a saved value and don't call
R_Traceback() if it doesn't match
- Rewrite win32_segv in terms of StringCcbPrintf to static storage and
WriteFile(GetStdHandle(STD_ERROR_HANDLE), ...), which may be too much
Attached is a crude first draft to see if the approach is viable. If it
turns out to be a good idea, I can add the Rterm or thread ID checks, a
reentrancy guard, declare and export a special struct win32_segvinfo
from psignal.c, put all the crash reporting in win32_segv(), and move
the VEH setup into psignal.c's signal(). (Just don't want to waste the
effort if this proves ill-advised.)
Without the patch:
User using WIN-LGTSPJA3F1V MSYS /c/R/R-svn/src/gnuwin32
$ cat crash.c
void crash(void) { *(double*)42 = 42; }
User using WIN-LGTSPJA3F1V MSYS /c/R/R-svn/src/gnuwin32
$ ../../bin/R -q -s -e 'dyn.load("crash.dll"); .C("crash")'
Segmentation fault # <-- printed by MSYS2 shell
With the patch:
User using WIN-LGTSPJA3F1V MSYS /c/R/R-svn/src/gnuwin32
$ ../../bin/R -q -s -e 'dyn.load("crash.dll"); .C("crash")'
*** caught access violation at program counter 0x00007ff911c61387 ***
accessing address 0x000000000000002a, action: write
Traceback:
1: .C("crash")
Segmentation fault
With the patch applied, I am not seeing changes in make check-devel or
package checks for V8. Couldn't test rJava yet.
--
Best regards,
Ivan
[1]
https://stat.ethz.ch/pipermail/r-package-devel/2024q2/010919.html
[2]
https://stat.ethz.ch/pipermail/r-package-devel/2024q2/010872.html
[3]
https://learn.microsoft.com/en-us/windows/win32/debug/vectored-exception-handling
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: veh-segv.patch
URL: <https://stat.ethz.ch/pipermail/r-devel/attachments/20240630/b0d8fbd1/attachment.ksh>
More information about the R-devel
mailing list