Skip to content

Commit 70ba1e5

Browse files
Address sanitizer/ndk28c (#118)
- up Android to ndk28c - add sanitizer builds to macOS and Linux - up AndroidExtensions commit id - fix uint16_t / char16_ casting - up macOS13 (soon deprecated) to macOS14 - use clang for sanitizer on Linux ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80578 ) - disable vptr check for `ObjectWrap<T>::ObjectWrap` (false positive)
1 parent e550dff commit 70ba1e5

File tree

9 files changed

+111
-20
lines changed

9 files changed

+111
-20
lines changed

.github/azure-pipelines.yml

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ schedules:
1414

1515
variables:
1616
- name: ndkVersion
17-
value: 25.2.9519653
17+
value: 28.2.13676358
1818

1919
jobs:
2020
# WIN32
@@ -85,6 +85,13 @@ jobs:
8585
vmImage: 'macOS-latest'
8686
xCodeVersion: 16.4
8787

88+
- template: jobs/macos.yml
89+
parameters:
90+
name: 'macOS_Xcode164_Sanitizers'
91+
vmImage: 'macOS-latest'
92+
xCodeVersion: 16.4
93+
enableSanitizers: true
94+
8895
# iOS
8996
- template: jobs/ios.yml
9097
parameters:
@@ -96,9 +103,24 @@ jobs:
96103
- template: jobs/ios.yml
97104
parameters:
98105
name: 'iOS_Xcode152'
99-
vmImage: 'macOS-13'
106+
vmImage: 'macOS-14'
100107
xCodeVersion: 15.2
101-
simulator: 'iPhone 14'
108+
simulator: 'iPhone 15'
102109

103110
# Linux
104-
- template: jobs/linux.yml
111+
- template: jobs/linux.yml
112+
parameters:
113+
name: Ubuntu_gcc
114+
115+
- template: jobs/linux.yml
116+
parameters:
117+
name: Ubuntu_clang
118+
CC: clang
119+
CXX: clang++
120+
121+
- template: jobs/linux.yml
122+
parameters:
123+
name: Ubuntu_Sanitizers_clang
124+
enableSanitizers: true
125+
CC: clang
126+
CXX: clang++

.github/jobs/android.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
parameters:
22
- name: name
33
type: string
4+
default: ''
45
- name: jsEngine
56
type: string
7+
default: ''
68

79
jobs:
810
- job: ${{parameters.name}}
911
timeoutInMinutes: 30
1012

1113
pool:
12-
vmImage: macos-13
14+
vmImage: macos-14
1315

1416
steps:
1517
- script: |

.github/jobs/linux.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
1+
parameters:
2+
name: ''
3+
enableSanitizers: false
4+
CC: gcc
5+
CXX: g++
6+
17
jobs:
2-
- job: ubuntu
8+
- job: ${{parameters.name}}
39
timeoutInMinutes: 15
410

511
pool:
612
vmImage: ubuntu-latest
713

14+
variables:
15+
SANITIZER_FLAG: ${{ coalesce(replace(format('{0}', parameters.enableSanitizers), 'True', 'ON'), 'OFF') }}
16+
817
steps:
918
- script: |
1019
sudo apt-get update
11-
sudo apt-get install libjavascriptcoregtk-4.1-dev libcurl4-openssl-dev ninja-build
20+
sudo apt-get install libjavascriptcoregtk-4.1-dev libcurl4-openssl-dev ninja-build clang
1221
displayName: 'Install packages'
1322
14-
- script: cmake -B Build/ubuntu -GNinja -D CMAKE_BUILD_TYPE=RelWithDebInfo
23+
- script: |
24+
export CC=${{parameters.CC}}
25+
export CXX=${{parameters.CXX}}
26+
cmake -B Build/ubuntu -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_SANITIZERS=$(SANITIZER_FLAG) -D CMAKE_C_COMPILER=${{parameters.CC}} -D CMAKE_CXX_COMPILER=${{parameters.CXX}}
1527
displayName: 'Configure CMake'
1628
1729
- script: |

.github/jobs/macos.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ parameters:
22
name: ''
33
vmImage: ''
44
xCodeVersion: ''
5+
enableSanitizers: false
56

67
jobs:
78
- job: ${{parameters.name}}
@@ -10,13 +11,16 @@ jobs:
1011
pool:
1112
vmImage: ${{parameters.vmImage}}
1213

14+
variables:
15+
SANITIZER_FLAG: ${{ coalesce(replace(format('{0}', parameters.enableSanitizers), 'True', 'ON'), 'OFF') }}
16+
1317
steps:
1418
- script: |
1519
sudo xcode-select --switch /Applications/Xcode_${{parameters.xCodeVersion}}.app/Contents/Developer
1620
displayName: 'Select Xcode ${{parameters.xCodeVersion}}'
1721
1822
- script: |
19-
cmake -B Build/macOS -GXcode
23+
cmake -B Build/macOS -G Xcode -D ENABLE_SANITIZERS=$(SANITIZER_FLAG)
2024
displayName: 'Configure CMake'
2125
2226
- task: Xcode@5

CMakeLists.txt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ FetchContent_Declare(arcana.cpp
1414
GIT_TAG c726dbe58713eda65bfb139c257093c43479b894)
1515
FetchContent_Declare(AndroidExtensions
1616
GIT_REPOSITORY https://github.com/BabylonJS/AndroidExtensions.git
17-
GIT_TAG 7d88a601fda9892791e7b4e994e375e049615688)
17+
GIT_TAG f7ed149b5360cc8a4908fece66607c5ce1e6095b)
1818
FetchContent_Declare(asio
1919
GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git
2020
GIT_TAG f693a3eb7fe72a5f19b975289afc4f437d373d9c)
@@ -73,6 +73,31 @@ option(JSRUNTIMEHOST_POLYFILL_ABORT_CONTROLLER "Include JsRuntimeHost Polyfills
7373
option(JSRUNTIMEHOST_POLYFILL_WEBSOCKET "Include JsRuntimeHost Polyfill WebSocket." ON)
7474
option(JSRUNTIMEHOST_POLYFILL_BLOB "Include JsRuntimeHost Polyfill Blob." ON)
7575

76+
# Sanitizers
77+
option(ENABLE_SANITIZERS "Enable AddressSanitizer and UBSan" OFF)
78+
79+
if(ENABLE_SANITIZERS)
80+
set(ENABLE_RTTI ON CACHE BOOL "" FORCE)
81+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
82+
set(SANITIZERS "address,undefined")
83+
# Check for Clang since vptr and fdsan are Clang-specific
84+
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
85+
list(APPEND SANITIZERS "vptr")
86+
# FDSan only works on Android builds with Clang
87+
if (ANDROID)
88+
list(APPEND SANITIZERS "fdsan")
89+
endif()
90+
endif()
91+
92+
string(JOIN "," SANITIZER_FLAGS ${SANITIZERS})
93+
94+
add_compile_options(-fsanitize=${SANITIZER_FLAGS} -fno-omit-frame-pointer)
95+
add_link_options(-fsanitize=${SANITIZER_FLAGS})
96+
else()
97+
message(WARNING "Sanitizers not supported on this compiler.")
98+
endif()
99+
endif()
100+
76101
# --------------------------------------------------
77102

78103
FetchContent_MakeAvailable_With_Message(arcana.cpp)

Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,9 @@ namespace Babylon
426426
}
427427
v8::Local<v8::String> string_value = v8::Local<v8::String>::Cast(value);
428428
int len = string_value->Length();
429-
std::basic_string<uint16_t> buffer(len, '\0');
430-
string_value->Write(v8::Isolate::GetCurrent(), &buffer[0], 0, len);
431-
return v8_inspector::StringBuffer::create(
432-
v8_inspector::StringView(buffer.data(), len));
429+
std::basic_string<char16_t> buffer(len, '\0');
430+
string_value->Write(v8::Isolate::GetCurrent(), reinterpret_cast<uint16_t*>(&buffer[0]), 0, len); // Write expects uint16_t* but the template parameter is char16_t
431+
return v8_inspector::StringBuffer::create(v8_inspector::StringView(reinterpret_cast<uint16_t*>(buffer.data()), len));
433432
}
434433

435434
bool AgentImpl::AppendMessage(

Core/Node-API/Include/Shared/napi/napi-inl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4494,8 +4494,11 @@ inline napi_value InstanceWrap<T>::WrappedMethod(
44944494
////////////////////////////////////////////////////////////////////////////////
44954495
// ObjectWrap<T> class
44964496
////////////////////////////////////////////////////////////////////////////////
4497-
44984497
template <typename T>
4498+
// [BABYLON-NATIVE-ADDITION]
4499+
#ifndef _MSC_VER
4500+
__attribute__((no_sanitize("vptr")))
4501+
#endif
44994502
inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
45004503
napi_env env = callbackInfo.Env();
45014504
napi_value wrapper = callbackInfo.This();

Core/Node-API/Source/js_native_api_javascriptcore.cc

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ struct napi_callback_info__ {
1919
};
2020

2121
namespace {
22+
size_t jschar_length(const JSChar* str) {
23+
size_t len = 0;
24+
while (str[len] != 0) { ++len; }
25+
return len;
26+
}
27+
2228
class JSString {
2329
public:
2430
JSString(const JSString&) = delete;
@@ -33,7 +39,7 @@ namespace {
3339
}
3440

3541
JSString(const JSChar* string, size_t length = NAPI_AUTO_LENGTH)
36-
: _string{JSStringCreateWithCharacters(string, length == NAPI_AUTO_LENGTH ? std::char_traits<JSChar>::length(string) : length)} {
42+
: _string{JSStringCreateWithCharacters(string, length == NAPI_AUTO_LENGTH ? jschar_length(string) : length)} {
3743
}
3844

3945
~JSString() {
@@ -1658,9 +1664,15 @@ napi_status napi_get_value_int32(napi_env env, napi_value value, int32_t* result
16581664
CHECK_ARG(env, result);
16591665

16601666
JSValueRef exception{};
1661-
*result = static_cast<int32_t>(JSValueToNumber(env->context, ToJSValue(value), &exception));
1667+
1668+
double num = JSValueToNumber(env->context, ToJSValue(value), &exception);
16621669
CHECK_JSC(env, exception);
16631670

1671+
if (std::isfinite(num)) {
1672+
*result = static_cast<int32_t>(num);
1673+
} else {
1674+
*result = 0;
1675+
}
16641676
return napi_ok;
16651677
}
16661678

@@ -1670,9 +1682,15 @@ napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* resu
16701682
CHECK_ARG(env, result);
16711683

16721684
JSValueRef exception{};
1673-
*result = static_cast<uint32_t>(JSValueToNumber(env->context, ToJSValue(value), &exception));
1685+
1686+
double num = JSValueToNumber(env->context, ToJSValue(value), &exception);
16741687
CHECK_JSC(env, exception);
16751688

1689+
if (std::isfinite(num)) {
1690+
*result = static_cast<uint32_t>(num);
1691+
} else {
1692+
*result = 0;
1693+
}
16761694
return napi_ok;
16771695
}
16781696

Polyfills/Blob/Source/Blob.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ namespace Babylon::Polyfills::Internal
7878
Napi::Value Blob::ArrayBuffer(const Napi::CallbackInfo&)
7979
{
8080
const auto arrayBuffer = Napi::ArrayBuffer::New(Env(), m_data.size());
81-
std::memcpy(arrayBuffer.Data(), m_data.data(), m_data.size());
81+
if (m_data.data())
82+
{
83+
std::memcpy(arrayBuffer.Data(), m_data.data(), m_data.size());
84+
}
8285

8386
const auto deferred = Napi::Promise::Deferred::New(Env());
8487
deferred.Resolve(arrayBuffer);
@@ -88,7 +91,10 @@ namespace Babylon::Polyfills::Internal
8891
Napi::Value Blob::Bytes(const Napi::CallbackInfo&)
8992
{
9093
const auto arrayBuffer = Napi::ArrayBuffer::New(Env(), m_data.size());
91-
std::memcpy(arrayBuffer.Data(), m_data.data(), m_data.size());
94+
if (m_data.data())
95+
{
96+
std::memcpy(arrayBuffer.Data(), m_data.data(), m_data.size());
97+
}
9298
const auto uint8Array = Napi::Uint8Array::New(Env(), m_data.size(), arrayBuffer, 0);
9399

94100
const auto deferred = Napi::Promise::Deferred::New(Env());

0 commit comments

Comments
 (0)