Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/tsan_suppressions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ThreadSanitizer suppressions for JsRuntimeHost
#
# These suppress data races internal to third-party libraries that we cannot fix.
# TSan on macOS (JavaScriptCore via Xcode) passes clean — these suppressions are
# only needed for the Ubuntu JSC build (libjavascriptcoregtk).

# JavaScriptCore internal races in libjavascriptcoregtk.
# Races manifest in TSan interceptors (free/malloc/memcpy/close) called from
# JSC's JIT worker threads. function-name suppressions are needed because the
# top frame is a libc interceptor attributed to UnitTests, not libjavascriptcoregtk.
called_from_lib:libjavascriptcoregtk
race:free
race:close
race:memcpy

# JSC signal handler that doesn't save/restore errno
signal:libjavascriptcoregtk
15 changes: 15 additions & 0 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ on:
required: false
type: boolean
default: false
enable-thread-sanitizer:
required: false
type: boolean
default: false

jobs:
build:
Expand All @@ -36,6 +40,7 @@ jobs:
cmake -B Build/ubuntu -G Ninja \
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
-D ENABLE_SANITIZERS=${{ inputs.enable-sanitizers && 'ON' || 'OFF' }} \
-D ENABLE_THREAD_SANITIZER=${{ inputs.enable-thread-sanitizer && 'ON' || 'OFF' }} \
-D CMAKE_C_COMPILER=${{ inputs.cc }} \
-D CMAKE_CXX_COMPILER=${{ inputs.cxx }}

Expand All @@ -45,3 +50,13 @@ jobs:
- name: Run Tests
working-directory: Build/ubuntu/Tests/UnitTests
run: ./UnitTests
env:
TSAN_OPTIONS: ${{ inputs.enable-thread-sanitizer && format('suppressions={0}/.github/tsan_suppressions.txt', github.workspace) || '' }}
# JSC's concurrent GC on Linux uses SIGUSR1 + sem_wait to suspend mutator
# threads at safepoints. TSan's signal interception delays SIGUSR1 delivery
# indefinitely, deadlocking the Collector Thread's sem_wait. Disabling the
# concurrent collector removes the dedicated Collector Thread, so GC runs
# on the mutator without cross-thread signals. macOS JSC uses Mach
# thread_suspend() and is unaffected.
JSC_useConcurrentGC: ${{ inputs.enable-thread-sanitizer && '0' || '' }}

10 changes: 9 additions & 1 deletion .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ on:
required: false
type: boolean
default: false
enable-thread-sanitizer:
required: false
type: boolean
default: false

jobs:
build:
Expand All @@ -28,11 +32,15 @@ jobs:
- name: Configure CMake
run: |
cmake -B Build/macOS -G Xcode \
-D ENABLE_SANITIZERS=${{ inputs.enable-sanitizers && 'ON' || 'OFF' }}
-D ENABLE_SANITIZERS=${{ inputs.enable-sanitizers && 'ON' || 'OFF' }} \
-D ENABLE_THREAD_SANITIZER=${{ inputs.enable-thread-sanitizer && 'ON' || 'OFF' }}

- name: Build
run: cmake --build Build/macOS --target UnitTests --config RelWithDebInfo

- name: Run Tests
working-directory: Build/macOS/Tests/UnitTests/RelWithDebInfo
run: ./UnitTests
env:
TSAN_OPTIONS: ${{ inputs.enable-thread-sanitizer && format('suppressions={0}/.github/tsan_suppressions.txt', github.workspace) || '' }}

15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ jobs:
runs-on: macos-latest
enable-sanitizers: true

macOS_Xcode164_ThreadSanitizer:
uses: ./.github/workflows/build-macos.yml
with:
xcode-version: '16.4'
runs-on: macos-latest
enable-thread-sanitizer: true


# ── iOS ───────────────────────────────────────────────────────
iOS_Xcode164:
uses: ./.github/workflows/build-ios.yml
Expand Down Expand Up @@ -114,3 +122,10 @@ jobs:
cc: clang
cxx: clang++
enable-sanitizers: true

Ubuntu_ThreadSanitizer_clang:
uses: ./.github/workflows/build-linux.yml
with:
cc: clang
cxx: clang++
enable-thread-sanitizer: true
18 changes: 16 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ FetchContent_Declare(AndroidExtensions
EXCLUDE_FROM_ALL)
FetchContent_Declare(arcana.cpp
GIT_REPOSITORY https://github.com/microsoft/arcana.cpp.git
GIT_TAG b9bf9d85fce37d5fc9dbfc4a4dc5e1531bee215a
GIT_TAG 0b9f9b6d761909fbca9d3ab1f2d8ff1c3d25ed3d
EXCLUDE_FROM_ALL)
FetchContent_Declare(asio
GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git
Expand All @@ -37,7 +37,7 @@ FetchContent_Declare(llhttp
EXCLUDE_FROM_ALL)
FetchContent_Declare(UrlLib
GIT_REPOSITORY https://github.com/BabylonJS/UrlLib.git
GIT_TAG 880c2575e57ca0b59068ecc4860f185b9970e0ce
GIT_TAG d251ad44015e1ee6cd071514cb863d8ffc220f16
EXCLUDE_FROM_ALL)
# --------------------------------------------------

Expand Down Expand Up @@ -85,6 +85,11 @@ option(JSRUNTIMEHOST_POLYFILL_TEXTDECODER "Include JsRuntimeHost Polyfill TextDe

# Sanitizers
option(ENABLE_SANITIZERS "Enable AddressSanitizer and UBSan" OFF)
option(ENABLE_THREAD_SANITIZER "Enable ThreadSanitizer" OFF)

if(ENABLE_SANITIZERS AND ENABLE_THREAD_SANITIZER)
message(FATAL_ERROR "ENABLE_SANITIZERS and ENABLE_THREAD_SANITIZER cannot be used together.")
endif()

if(ENABLE_SANITIZERS)
set(ENABLE_RTTI ON CACHE BOOL "" FORCE)
Expand All @@ -111,6 +116,15 @@ if(ENABLE_SANITIZERS)
endif()
endif()

if(ENABLE_THREAD_SANITIZER)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
add_compile_options(-fsanitize=thread -fno-omit-frame-pointer)
add_link_options(-fsanitize=thread)
else()
message(WARNING "ThreadSanitizer not supported on this compiler.")
endif()
endif()

# --------------------------------------------------

if(JSRUNTIMEHOST_TESTS)
Expand Down
Loading