Skip to content

Commit

Permalink
Signals.cpp implementation for Windows
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=259108

Reviewed by Yusuke Suzuki.

Signals is implemented using a VectoredExceptionHandler on Windows, so
we cannot support all the Signal types as the other OS's. We need
support for AccessFault, which is used for WASM memory.

Test: Tools/TestWebKitAPI/Tests/WTF/Signals.cpp

* Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp:
* Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h:
* Source/WTF/wtf/PlatformJSCOnly.cmake:
* Source/WTF/wtf/PlatformWin.cmake:
* Source/WTF/wtf/WTFConfig.h:
* Source/WTF/wtf/threads/Signals.cpp:
(WTF::toSystemSignal):
(WTF::fromSystemSignal):
* Source/WTF/wtf/threads/Signals.h:
(WTF::toSystemSignal): Deleted.
(WTF::fromSystemSignal): Deleted.
* Source/WTF/wtf/win/SignalsWin.cpp: Added.
(WTF::SignalHandlers::add):
(WTF::SignalHandlers::forEachHandler const):
(WTF::fromSystemException):
(WTF::vectoredHandler):
(WTF::addSignalHandler):
(WTF::activateSignalHandlersFor):
(WTF::SignalHandlers::initialize):
* Tools/TestWebKitAPI/CMakeLists.txt:
* Tools/TestWebKitAPI/Tests/WTF/Signals.cpp:
(TEST):

Canonical link: https://commits.webkit.org/266716@main
  • Loading branch information
iangrunert authored and donny-dont committed Aug 9, 2023
1 parent 6b2ef31 commit 66b9bc9
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 57 deletions.
5 changes: 2 additions & 3 deletions Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
#include "config.h"
#include "WasmFaultSignalHandler.h"

// FIXME: https://bugs.webkit.org/show_bug.cgi?id=259108 Support signal handlers on Windows
#if ENABLE(WEBASSEMBLY) && OS(UNIX)
#if ENABLE(WEBASSEMBLY)

#include "ExecutableAllocator.h"
#include "LLIntData.h"
Expand Down Expand Up @@ -133,5 +132,5 @@ void prepareSignalingMemory()

} } // namespace JSC::Wasm

#endif // ENABLE(WEBASSEMBLY) && OS(UNIX)
#endif // ENABLE(WEBASSEMBLY)

2 changes: 1 addition & 1 deletion Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace JSC {

namespace Wasm {

#if ENABLE(WEBASSEMBLY) && OS(UNIX)
#if ENABLE(WEBASSEMBLY)
void activateSignalingMemory();
void prepareSignalingMemory();
#else
Expand Down
1 change: 1 addition & 0 deletions Source/WTF/wtf/PlatformJSCOnly.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if (WIN32)
win/MainThreadWin.cpp
win/OSAllocatorWin.cpp
win/PathWalker.cpp
win/SignalsWin.cpp
win/ThreadingWin.cpp
)
list(APPEND WTF_PUBLIC_HEADERS
Expand Down
1 change: 1 addition & 0 deletions Source/WTF/wtf/PlatformWin.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ list(APPEND WTF_SOURCES
win/OSAllocatorWin.cpp
win/PathWalker.cpp
win/RunLoopWin.cpp
win/SignalsWin.cpp
win/ThreadingWin.cpp
win/Win32Handle.cpp
)
Expand Down
2 changes: 0 additions & 2 deletions Source/WTF/wtf/WTFConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ struct Config {
bool isThreadSuspendResumeSignalConfigured;
int sigThreadSuspendResume;
#endif
#if OS(UNIX)
SignalHandlers signalHandlers;
#endif
PtrTagLookup* ptrTagLookupHead;

uint64_t spaceForExtensions[1];
Expand Down
33 changes: 32 additions & 1 deletion Source/WTF/wtf/threads/Signals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "config.h"
#include <wtf/threads/Signals.h>

// FIXME: https://bugs.webkit.org/show_bug.cgi?id=259108 Support signal handlers on Windows
#if OS(UNIX)

#if HAVE(MACH_EXCEPTIONS)
Expand Down Expand Up @@ -336,6 +335,38 @@ void registerThreadForMachExceptionHandling(Thread& thread)

#endif // HAVE(MACH_EXCEPTIONS)

inline std::tuple<int, std::optional<int>> toSystemSignal(Signal signal)
{
switch (signal) {
case Signal::AccessFault: return std::make_tuple(SIGSEGV, SIGBUS);
case Signal::IllegalInstruction: return std::make_tuple(SIGILL, std::nullopt);
case Signal::Usr: return std::make_tuple(SIGUSR2, std::nullopt);
case Signal::FloatingPoint: return std::make_tuple(SIGFPE, std::nullopt);
case Signal::Breakpoint: return std::make_tuple(SIGTRAP, std::nullopt);
#if !OS(DARWIN)
case Signal::Abort: return std::make_tuple(SIGABRT, std::nullopt);
#endif
default: break;
}
RELEASE_ASSERT_NOT_REACHED();
}

inline Signal fromSystemSignal(int signal)
{
switch (signal) {
case SIGSEGV: return Signal::AccessFault;
case SIGBUS: return Signal::AccessFault;
case SIGFPE: return Signal::FloatingPoint;
case SIGTRAP: return Signal::Breakpoint;
case SIGILL: return Signal::IllegalInstruction;
case SIGUSR2: return Signal::Usr;
#if !OS(DARWIN)
case SIGABRT: return Signal::Abort;
#endif
default: return Signal::Unknown;
}
}

inline size_t offsetForSystemSignal(int sig)
{
Signal signal = fromSystemSignal(sig);
Expand Down
65 changes: 16 additions & 49 deletions Source/WTF/wtf/threads/Signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,25 @@

#pragma once

#include <wtf/Function.h>
#include <wtf/Lock.h>
#include <wtf/PlatformRegisters.h>

#if OS(UNIX)

#include <signal.h>
#include <tuple>
#include <wtf/Function.h>
#include <wtf/Lock.h>
#include <wtf/PlatformRegisters.h>

#if HAVE(MACH_EXCEPTIONS)
#include <mach/exception_types.h>
#endif
#endif // OS(UNIX)

namespace WTF {

// Note that SIGUSR1 is used in Pthread-based ports except for Darwin to suspend and resume threads.
enum class Signal {
#if OS(UNIX)
// Usr will always chain to any non-default handler install before us. Since there is no way to know
// if a signal was intended exclusively for us.
Usr,
Expand All @@ -56,39 +59,14 @@ enum class Signal {
AccessFault, // For posix this is both SIGSEGV and SIGBUS
NumberOfSignals = AccessFault + 2, // AccessFault is really two signals.
Unknown = NumberOfSignals
};

inline std::tuple<int, std::optional<int>> toSystemSignal(Signal signal)
{
switch (signal) {
case Signal::AccessFault: return std::make_tuple(SIGSEGV, SIGBUS);
case Signal::IllegalInstruction: return std::make_tuple(SIGILL, std::nullopt);
case Signal::Usr: return std::make_tuple(SIGUSR2, std::nullopt);
case Signal::FloatingPoint: return std::make_tuple(SIGFPE, std::nullopt);
case Signal::Breakpoint: return std::make_tuple(SIGTRAP, std::nullopt);
#if !OS(DARWIN)
case Signal::Abort: return std::make_tuple(SIGABRT, std::nullopt);
#endif
default: break;
}
RELEASE_ASSERT_NOT_REACHED();
}

inline Signal fromSystemSignal(int signal)
{
switch (signal) {
case SIGSEGV: return Signal::AccessFault;
case SIGBUS: return Signal::AccessFault;
case SIGFPE: return Signal::FloatingPoint;
case SIGTRAP: return Signal::Breakpoint;
case SIGILL: return Signal::IllegalInstruction;
case SIGUSR2: return Signal::Usr;
#if !OS(DARWIN)
case SIGABRT: return Signal::Abort;
#else
FloatingPoint,
IllegalInstruction,
AccessFault,
NumberOfSignals = AccessFault + 1,
Unknown = NumberOfSignals
#endif
default: return Signal::Unknown;
}
}
};

enum class SignalAction {
Handled,
Expand Down Expand Up @@ -131,7 +109,10 @@ struct SignalHandlers {
#endif
uint8_t numberOfHandlers[numberOfSignals];
SignalHandlerMemory handlers[numberOfSignals][maxNumberOfHandlers];

#if OS(UNIX)
struct sigaction oldActions[numberOfSignals];
#endif
};

// Call this method whenever you want to add a signal handler. This function needs to be called
Expand Down Expand Up @@ -167,23 +148,9 @@ using WTF::handleSignalsWithMach;

using WTF::Signal;
using WTF::SigInfo;
using WTF::toSystemSignal;
using WTF::fromSystemSignal;
using WTF::SignalAction;
using WTF::SignalHandler;
using WTF::addSignalHandler;
using WTF::activateSignalHandlersFor;

#else // not OS(UNIX)

namespace WTF {

inline void initializeSignalHandling() { }
inline void disableSignalHandling() { }

} // namespace WTF

#endif // OS(UNIX)

using WTF::initializeSignalHandling;
using WTF::disableSignalHandling;
154 changes: 154 additions & 0 deletions Source/WTF/wtf/win/SignalsWin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (C) 2023 Ian Grunert <ian.grunert@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include <wtf/threads/Signals.h>

#if OS(WINDOWS)

#include <cstdio>
#include <mutex>
#include <signal.h>
#include <winnt.h>

#include <wtf/Atomics.h>
#include <wtf/DataLog.h>
#include <wtf/MathExtras.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/PlatformRegisters.h>
#include <wtf/ThreadGroup.h>
#include <wtf/Threading.h>
#include <wtf/WTFConfig.h>

namespace WTF {

void SignalHandlers::add(Signal signal, SignalHandler&& handler)
{
Config::AssertNotFrozenScope assertScope;
static Lock lock;
Locker locker { lock };

size_t signalIndex = static_cast<size_t>(signal);
size_t nextFree = numberOfHandlers[signalIndex];
RELEASE_ASSERT(nextFree < maxNumberOfHandlers);
SignalHandlerMemory* memory = &handlers[signalIndex][nextFree];
new (memory) SignalHandler(WTFMove(handler));

// We deliberately do not want to increment the count until after we've
// fully initialized the memory. This way, forEachHandler() won't see a
// partially initialized handler.
storeStoreFence();
numberOfHandlers[signalIndex]++;
loadLoadFence();
}

template<typename Func>
inline void SignalHandlers::forEachHandler(Signal signal, const Func& func) const
{
size_t signalIndex = static_cast<size_t>(signal);
size_t handlerIndex = numberOfHandlers[signalIndex];
while (handlerIndex--) {
auto* memory = const_cast<SignalHandlerMemory*>(&handlers[signalIndex][handlerIndex]);
const SignalHandler& handler = *bitwise_cast<SignalHandler*>(memory);
func(handler);
}
}

inline Signal fromSystemException(int signal)
{
switch (signal) {
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
return Signal::FloatingPoint;
case EXCEPTION_ILLEGAL_INSTRUCTION:
return Signal::IllegalInstruction;
case EXCEPTION_ACCESS_VIOLATION:
return Signal::AccessFault;
default:
return Signal::Unknown;
}
}

LONG WINAPI vectoredHandler(struct _EXCEPTION_POINTERS *exceptionInfo)
{
Signal signal = fromSystemException(exceptionInfo->ExceptionRecord->ExceptionCode);
SignalHandlers& handlers = g_wtfConfig.signalHandlers;

SigInfo sigInfo;
if (signal == Signal::AccessFault) {
// The second array element specifies the virtual address of the inaccessible data.
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
sigInfo.faultingAddress = reinterpret_cast<void*>(exceptionInfo->ExceptionRecord->ExceptionInformation[1]);
}

PlatformRegisters& registers = *(exceptionInfo->ContextRecord);

long result = EXCEPTION_EXECUTE_HANDLER;
handlers.forEachHandler(signal, [&] (const SignalHandler& handler) {
switch (handler(signal, sigInfo, registers)) {
case SignalAction::Handled:
result = EXCEPTION_CONTINUE_EXECUTION;
break;
default:
break;
}
});

return result;
}

void addSignalHandler(Signal signal, SignalHandler&& handler)
{
Config::AssertNotFrozenScope assertScope;
SignalHandlers& handlers = g_wtfConfig.signalHandlers;
ASSERT(signal < Signal::Unknown);

static std::once_flag initializeOnceFlags[static_cast<size_t>(Signal::NumberOfSignals)];
std::call_once(initializeOnceFlags[static_cast<size_t>(signal)], [&] {
Config::AssertNotFrozenScope assertScope;
AddVectoredExceptionHandler(1, vectoredHandler);
});

handlers.add(signal, WTFMove(handler));
}

void activateSignalHandlersFor(Signal signal)
{
UNUSED_PARAM(signal);
}

void SignalHandlers::initialize()
{
// noop
}

} // namespace WTF

#endif // OS(WINDOWS)
1 change: 1 addition & 0 deletions Tools/TestWebKitAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ set(TestWTF_SOURCES
Tests/WTF/ScopedLambda.cpp
Tests/WTF/SentinelLinkedList.cpp
Tests/WTF/SetForScope.cpp
Tests/WTF/Signals.cpp
Tests/WTF/StackTraceTest.cpp
Tests/WTF/StdLibExtrasTests.cpp
Tests/WTF/StringBuilder.cpp
Expand Down
Loading

0 comments on commit 66b9bc9

Please sign in to comment.