-
Notifications
You must be signed in to change notification settings - Fork 102
Handle signals on Windows in exit tests. #766
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
Conversation
@swift-ci test |
@swift-ci test |
e30e32a
to
65f4091
Compare
@swift-ci test |
@swift-ci test |
1 similar comment
@swift-ci test |
Some additional documentation blobs I'll put here for posterity in case we decide we want to add them: For ///
/// On Windows, the system uses [Structured Exception Handling](https://learn.microsoft.com/en-us/windows/win32/debug/structured-exception-handling)
/// to handle some error conditions. If an exception is raised and is not
/// handled, it will terminate the current process with an exit code equal to
/// that exception's [exception code](https://learn.microsoft.com/en-us/windows/win32/debug/getexceptioncode). For ///
/// ## Signal handling on Windows
///
/// On Windows, by default, the C runtime will terminate a process with exit
/// code `3` if a raised signal is not handled, exactly as if `exit(3)` were
/// called.
///
/// In order to accurately report the exit condition of an exit test,
/// the testing library installs signal handlers for all signals supported by
/// Windows before an exit test runs. If your code calls `signal(n, SIG_DFL)`
/// to reset the signal handler for some signal _n_, the system will remove
/// the signal handler installed by the testing library.
///
/// If you cannot avoid resetting the signal handler in an exit test to
/// `SIG_DFL`, pass ``failure`` instead of ``signal(_:)`` when you call
/// ``expect(exitsWith:_:sourceLocation:performing:)`` or
/// ``require(exitsWith:_:sourceLocation:performing:)``. |
This PR adds support for handling signals as distinct exit conditions on Windows. Previously, we didn't support them because Windows itself has minimal support. However, through the judicious use of "stuffing a bunch of bits into a 32-bit field", we are able to propagate raised signals out of the child process and detect them in the parent process. We do this by installing our own signal handlers for all signals supported on Windows, then masking the caught signal against an `NTSTATUS` severity and facility that are unlikely to be reported by the system in practice. In the parent process, we look for exit codes that match these values and extract the signal from them when found. Because the namespace for exit codes on Windows is shared with uncaught VEH/SEH exceptions (which are propagated to the parent process as `NTSTATUS` codes), there is the potential for conflict with some hypothetical _real_ exception code, but I'm taking a gamble here that my choice of `NTSTATUS` facility is unique. (Bonus points for there not being convenient macros to construct an `NTSTATUS` code anywhere in the Windows SDK I can find.)
…thing internal by mistake
Co-authored-by: Saleem Abdulrasool <[email protected]>
fb9da8b
to
a94eea2
Compare
@swift-ci test |
1 similar comment
@swift-ci test |
@swift-ci test |
@swift-ci test |
On Windows, `NTSTATUS` is a typedef of `long`. On 32-bit Windows, `long` is imported into Swift as `Int` but on 64-bit Windows,it's imported as `Int32`. These types are layout-equivalent but not implicitly convertible, so we get errors on 32-bit Windows when using an `NTSTATUS` (i.e. `Int`) where a `CInt` (i.e. `Int32`) is expected. This PR changes the types of the constants introduced in #766 to be explicitly `CInt` so that they are usable on both flavours of Windows.
On Windows, `NTSTATUS` is a typedef of `long`. On 32-bit Windows, `long` is imported into Swift as `Int` but on 64-bit Windows,it's imported as `Int32`. These types are layout-equivalent but not implicitly convertible, so we get errors on 32-bit Windows when using an `NTSTATUS` (i.e. `Int`) where a `CInt` (i.e. `Int32`) is expected. This PR changes the types of the constants introduced in #766 to be explicitly `CInt` so that they are usable on both flavours of Windows. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
@grynspan I'm not sure but does it looks like the Windows CI broke: https://ci-external.swift.org/job/swift-main-windows-toolchain/734/consoleText?
|
That has already been resolved. See #776. |
Thanks @grynspan !! |
This PR adds support for handling signals as distinct exit conditions on Windows. Previously, we didn't support them because Windows itself has minimal support. However, through the judicious use of "stuffing a bunch of bits into a 32-bit field", we are able to propagate raised signals out of the child process and detect them in the parent process.
We do this by installing our own signal handlers for all signals supported on Windows, then masking the caught signal against an
NTSTATUS
severity and facility that are unlikely to be reported by the system in practice. In the parent process, we look for exit codes that match these values and extract the signal from them when found. Because the namespace for exit codes on Windows is shared with uncaught VEH/SEH exceptions (which are propagated to the parent process asNTSTATUS
codes), there is the potential for conflict with some hypothetical real exception code, but I'm taking a gamble here that my choice ofNTSTATUS
facility is unique.(Bonus points for there not being convenient macros to construct an
NTSTATUS
code anywhere in the Windows SDK I can find.)Checklist: