Skip to content

Commit ed3afde

Browse files
committed
test: Add cases with a blacklisted entities
* Add test case with function returning a struct which is blacklisted If a struct's metadata is missing it's not possible to silently ignore it and perform the call, because we don't know its size and cannot reliably allocate the stack frame for the cif. That's why we'll abort the call and throw a JS exception * Add test case with functions returning and taking as an argument objects from a blacklisted class. In this scenario the behavior is the same as with objects from private classes * Use Objective-C exceptions to propagate errors when filtered metadata is used and handle them in JSC callbacks * Update metadata generator to use native names in type encodings to allow correct discovery of interfaces and protocols when they have been filtered
1 parent a243aa7 commit ed3afde

38 files changed

Lines changed: 1168 additions & 912 deletions

src/NativeScript/CMakeLists.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ set(HEADER_FILES
120120
set(SOURCE_FILES
121121
Calling/FFICache.cpp
122122
Calling/FFICall.cpp
123-
Calling/FFICallPrototype.cpp
123+
Calling/FFICallPrototype.mm
124124
Calling/CFunctionWrapper.mm
125125
Calling/FFIFunctionCallback.mm
126126
Calling/FunctionWrapper.mm
@@ -148,25 +148,25 @@ set(SOURCE_FILES
148148
Marshalling/FFIType.cpp
149149
Marshalling/FunctionReference/FunctionReferenceConstructor.cpp
150150
Marshalling/FunctionReference/FunctionReferenceInstance.cpp
151-
Marshalling/FunctionReference/FunctionReferenceTypeConstructor.cpp
151+
Marshalling/FunctionReference/FunctionReferenceTypeConstructor.mm
152152
Marshalling/FunctionReference/FunctionReferenceTypeInstance.cpp
153153
Marshalling/Fundamentals/FFINumericTypes.mm
154154
Marshalling/Fundamentals/FFIPrimitiveTypes.cpp
155-
Marshalling/Pointer/PointerConstructor.cpp
155+
Marshalling/Pointer/PointerConstructor.mm
156156
Marshalling/Pointer/PointerInstance.cpp
157157
Marshalling/Pointer/PointerPrototype.cpp
158-
Marshalling/Record/RecordConstructor.cpp
158+
Marshalling/Record/RecordConstructor.mm
159159
Marshalling/Record/RecordField.cpp
160160
Marshalling/Record/RecordInstance.cpp
161161
Marshalling/Record/RecordPrototype.cpp
162162
Marshalling/Record/RecordPrototypeFunctions.cpp
163-
Marshalling/Reference/ReferenceConstructor.cpp
164-
Marshalling/Reference/ReferenceInstance.cpp
163+
Marshalling/Reference/ReferenceConstructor.mm
164+
Marshalling/Reference/ReferenceInstance.mm
165165
Marshalling/Reference/ReferencePrototype.cpp
166-
Marshalling/Reference/ReferenceTypeConstructor.cpp
166+
Marshalling/Reference/ReferenceTypeConstructor.mm
167167
Marshalling/Reference/ReferenceTypeInstance.cpp
168168
Marshalling/Reference/IndexedRefTypeInstance.cpp
169-
Marshalling/Reference/IndexedRefInstance.cpp
169+
Marshalling/Reference/IndexedRefInstance.mm
170170
Marshalling/Reference/IndexedRefPrototype.cpp
171171
Marshalling/Reference/ExtVectorTypeInstance.cpp
172172
Metadata/Metadata.mm
@@ -175,7 +175,7 @@ set(SOURCE_FILES
175175
ObjC/Block/ObjCBlockCall.mm
176176
ObjC/Block/ObjCBlockCallback.mm
177177
ObjC/Block/ObjCBlockType.mm
178-
ObjC/Block/ObjCBlockTypeConstructor.cpp
178+
ObjC/Block/ObjCBlockTypeConstructor.mm
179179
ObjC/Constructor/ObjCConstructorBase.mm
180180
ObjC/Constructor/ObjCConstructorCall.mm
181181
ObjC/Constructor/ObjCConstructorDerived.cpp

src/NativeScript/Calling/FFICallPrototype.cpp

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// FFICallPrototype.cpp
3+
// NativeScript
4+
//
5+
// Created by Yavor Georgiev on 25.09.15.
6+
// Copyright (c) 2015 Telerik. All rights reserved.
7+
//
8+
9+
#include "FFICallPrototype.h"
10+
#include "FFICall.h"
11+
#include "FunctionWrapper.h"
12+
#include "JSErrors.h"
13+
#include <JavaScriptCore/interpreter/Interpreter.h>
14+
15+
namespace NativeScript {
16+
using namespace JSC;
17+
18+
const ClassInfo FFICallPrototype::s_info = { "FFIFunction", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FFICallPrototype) };
19+
20+
EncodedJSValue JSC_HOST_CALL FFICallPrototypeFuncAsync(ExecState*);
21+
22+
void FFICallPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) {
23+
Base::finishCreation(vm);
24+
didBecomePrototype();
25+
26+
JSC_NATIVE_FUNCTION(Identifier::fromString(&vm, "async"), FFICallPrototypeFuncAsync, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
27+
}
28+
29+
EncodedJSValue JSC_HOST_CALL FFICallPrototypeFuncAsync(ExecState* execState) {
30+
NS_TRY {
31+
auto call = jsCast<FunctionWrapper*>(execState->thisValue());
32+
JSC::VM& vm = execState->vm();
33+
auto scope = DECLARE_THROW_SCOPE(vm);
34+
35+
JSValue array = execState->argument(1);
36+
37+
MarkedArgumentBuffer applyArgs;
38+
if (!array.isUndefinedOrNull()) {
39+
if (!array.isObject())
40+
return throwVMTypeError(execState, scope);
41+
if (isJSArray(array)) {
42+
if (asArray(array)->length() > JSC::maxArguments)
43+
return JSValue::encode(throwStackOverflowError(execState, scope));
44+
asArray(array)->fillArgList(execState, applyArgs);
45+
} else {
46+
unsigned length = asObject(array)->get(execState, vm.propertyNames->length).toUInt32(execState);
47+
if (length > JSC::maxArguments)
48+
return JSValue::encode(throwStackOverflowError(execState, scope));
49+
50+
for (unsigned i = 0; i < length; ++i)
51+
applyArgs.append(asObject(array)->get(execState, i));
52+
}
53+
}
54+
55+
return JSValue::encode(call->async(execState, execState->argument(0), applyArgs));
56+
}
57+
NS_CATCH_THROW_TO_JS(execState)
58+
59+
return JSValue::encode(jsUndefined());
60+
}
61+
} // namespace NativeScript

src/NativeScript/Calling/FFIFunctionCallback.mm

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "FFIFunctionCallback.h"
1010
#include "FFICallbackInlines.h"
1111
#include "FunctionReferenceTypeInstance.h"
12+
#include "JSErrors.h"
1213

1314
namespace NativeScript {
1415
using namespace JSC;
@@ -17,18 +18,21 @@
1718

1819
void FFIFunctionCallback::ffiClosureCallback(void* retValue, void** argValues, void* userData) {
1920
FFIFunctionCallback* functionCallback = reinterpret_cast<FFIFunctionCallback*>(userData);
21+
NS_TRY {
2022

21-
JSC::VM& vm = functionCallback->execState()->vm();
22-
auto scope = DECLARE_THROW_SCOPE(vm);
23+
JSC::VM& vm = functionCallback->execState()->vm();
24+
auto scope = DECLARE_THROW_SCOPE(vm);
2325

24-
MarkedArgumentBuffer arguments;
25-
functionCallback->marshallArguments(argValues, arguments, functionCallback);
26-
if (scope.exception()) {
27-
return;
28-
}
26+
MarkedArgumentBuffer arguments;
27+
functionCallback->marshallArguments(argValues, arguments, functionCallback);
28+
if (scope.exception()) {
29+
return;
30+
}
2931

30-
ASSERT(!arguments.hasOverflowed());
31-
functionCallback->callFunction(functionCallback->execState()->globalThisValue(), arguments, retValue);
32+
ASSERT(!arguments.hasOverflowed());
33+
functionCallback->callFunction(functionCallback->execState()->globalThisValue(), arguments, retValue);
34+
}
35+
NS_CATCH_THROW_TO_JS(functionCallback->execState());
3236
}
3337

3438
void FFIFunctionCallback::finishCreation(VM& vm, JSGlobalObject* globalObject, JSCell* function, FunctionReferenceTypeInstance* functionReferenceType) {

src/NativeScript/Calling/FunctionWrapper.mm

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "FFICache.h"
1010
#include "FFICall.h"
11+
#include "JSErrors.h"
1112
#include "ObjCTypes.h"
1213
#include <JavaScriptCore/JSObjectRef.h>
1314
#include <JavaScriptCore/JSPromiseDeferred.h>
@@ -70,45 +71,50 @@
7071
}
7172

7273
EncodedJSValue JSC_HOST_CALL FunctionWrapper::call(ExecState* execState) {
73-
FunctionWrapper* call = jsCast<FunctionWrapper*>(execState->callee().asCell());
74+
NS_TRY {
75+
FunctionWrapper* call = jsCast<FunctionWrapper*>(execState->callee().asCell());
7476

75-
const std::unique_ptr<FFICall>& c = Metadata::getProperFunctionFromContainer<std::unique_ptr<FFICall>>(call->functionsContainer(), execState->argumentCount(), [](const std::unique_ptr<FFICall>& fficall) { return static_cast<int>(fficall.get()->parametersCount()); });
76-
FFICall* callee = c.get();
77+
const std::unique_ptr<FFICall>& c = Metadata::getProperFunctionFromContainer<std::unique_ptr<FFICall>>(call->functionsContainer(), execState->argumentCount(), [](const std::unique_ptr<FFICall>& fficall) { return static_cast<int>(fficall.get()->parametersCount()); });
78+
FFICall* callee = c.get();
7779

78-
ASSERT(callee);
80+
ASSERT(callee);
7981

80-
FFICall::Invocation invocation(callee);
81-
ReleasePoolHolder releasePoolHolder(execState);
82-
83-
JSC::VM& vm = execState->vm();
82+
FFICall::Invocation invocation(callee);
83+
ReleasePoolHolder releasePoolHolder(execState);
8484

85-
[[TNSRuntime current] tryCollectGarbage];
85+
JSC::VM& vm = execState->vm();
8686

87-
auto scope = DECLARE_THROW_SCOPE(vm);
87+
[[TNSRuntime current] tryCollectGarbage];
8888

89-
callee->preCall(execState, invocation);
90-
if (scope.exception()) {
91-
return JSValue::encode(scope.exception());
92-
}
93-
94-
@try {
95-
{
96-
JSLock::DropAllLocks locksDropper(execState);
97-
ffi_call(callee->cif()->get(), FFI_FN(invocation.function), invocation.resultBuffer(), reinterpret_cast<void**>(invocation._buffer + callee->argsArrayOffset()));
98-
}
89+
auto scope = DECLARE_THROW_SCOPE(vm);
9990

91+
callee->preCall(execState, invocation);
10092
if (scope.exception()) {
101-
// in the ffi call the native method could reach javascript code throwing an error we don't need the code below to execute
10293
return JSValue::encode(scope.exception());
10394
}
10495

105-
JSValue result = callee->returnType().read(execState, invocation._buffer + callee->returnOffset(), callee->returnTypeCell().get());
96+
@try {
97+
{
98+
JSLock::DropAllLocks locksDropper(execState);
99+
ffi_call(callee->cif()->get(), FFI_FN(invocation.function), invocation.resultBuffer(), reinterpret_cast<void**>(invocation._buffer + callee->argsArrayOffset()));
100+
}
101+
102+
if (scope.exception()) {
103+
// in the ffi call the native method could reach javascript code throwing an error we don't need the code below to execute
104+
return JSValue::encode(scope.exception());
105+
}
106106

107-
callee->postCall(execState, invocation);
108-
return JSValue::encode(result);
109-
} @catch (NSException* exception) {
110-
return throwVMError(execState, scope, createErrorFromNSException([TNSRuntime current], execState, exception));
107+
JSValue result = callee->returnType().read(execState, invocation._buffer + callee->returnOffset(), callee->returnTypeCell().get());
108+
109+
callee->postCall(execState, invocation);
110+
return JSValue::encode(result);
111+
} @catch (NSException* exception) {
112+
return throwVMError(execState, scope, createErrorFromNSException([TNSRuntime current], execState, exception));
113+
}
111114
}
115+
NS_CATCH_THROW_TO_JS(execState)
116+
117+
return JSValue::encode(jsUndefined());
112118
}
113119

114120
JSObject* FunctionWrapper::async(ExecState* execState, JSValue thisValue, const ArgList& arguments) {

0 commit comments

Comments
 (0)