Skip to content
Open
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
1 change: 1 addition & 0 deletions test-app/app/src/main/assets/app/mainpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ shared.runRuntimeTests();
shared.runWorkerTests();
require("./tests/testWebAssembly");
require("./tests/testMultithreadedJavascript");
require("./tests/testWorkerTerminateDuringLoad");
require("./tests/testInterfaceDefaultMethods");
require("./tests/testInterfaceStaticMethods");
require("./tests/testMetadata");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
describe("Worker terminate during module load", function () {
var ITERATIONS = 3;
// Long enough to outlast the worker's isolate setup, short enough to keep
// the spec well inside the jasmine timeout.
var TERMINATE_AFTER = 150;
var SETTLE_AFTER = 250;

it("should not report an error or crash when terminate() interrupts the worker's module body", function (done) {
var errors = [];

function iteration(remaining) {
if (remaining === 0) {
expect(errors).toEqual([]);
done();
return;
}

var worker = new Worker("./workerTerminateDuringLoadWorker.js");
worker.onerror = function (e) {
errors.push(e.message);
};

setTimeout(function () {
worker.terminate();
setTimeout(function () {
iteration(remaining - 1);
}, SETTLE_AFTER);
}, TERMINATE_AFTER);
}

iteration(ITERATIONS);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Spins at module scope so a terminate() from the parent lands while this
// module body is still executing, which is the window the test targets.
var deadline = Date.now() + 5000;
while (Date.now() < deadline) {
}
10 changes: 6 additions & 4 deletions test-app/runtime/src/main/cpp/CallbackHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1496,12 +1496,14 @@ void CallbackHandlers::CallWorkerScopeOnErrorHandle(Isolate *isolate, TryCatch &
auto globalObject = context->Global();

// execute onerror handle if one is implemented
auto callback = globalObject->Get(context, ArgConverter::ConvertToV8String(isolate,
"onerror")).ToLocalChecked();
auto isEmpty = callback.IsEmpty();
Local<Value> callback;
if (!globalObject->Get(context, ArgConverter::ConvertToV8String(isolate, "onerror"))
.ToLocal(&callback)) {
return;
}
auto isFunction = callback->IsFunction();

if (!isEmpty && isFunction && !tc.Message().IsEmpty()) {
if (isFunction && !tc.Message().IsEmpty()) {
auto msg = tc.Message()->Get();
Local<Value> args1[] = {msg};

Expand Down
11 changes: 8 additions & 3 deletions test-app/runtime/src/main/cpp/ModuleInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,11 @@ Local<Object> ModuleInternal::LoadModule(Isolate* isolate, const string& moduleP
if (Util::EndsWith(modulePath, ".js")) {
auto script = LoadScript(isolate, modulePath, fullRequiredModulePath);

moduleFunc = script->Run(context).ToLocalChecked().As<Function>();
if (tc.HasCaught()) {
Local<Value> moduleFuncValue;
if (!script->Run(context).ToLocal(&moduleFuncValue) || tc.HasCaught()) {
throw NativeScriptException(tc, "Error running script " + modulePath);
}
moduleFunc = moduleFuncValue.As<Function>();
} else if (Util::EndsWith(modulePath, ".so")) {
auto handle = dlopen(modulePath.c_str(), RTLD_LAZY);
if (handle == nullptr) {
Expand Down Expand Up @@ -425,7 +426,11 @@ Local<Object> ModuleInternal::LoadModule(Isolate* isolate, const string& moduleP

auto thiz = Object::New(isolate);
auto extendsName = ArgConverter::ConvertToV8String(isolate, "__extends");
thiz->Set(context, extendsName, context->Global()->Get(context, extendsName).ToLocalChecked());
Local<Value> extendsFunc;
if (!context->Global()->Get(context, extendsName).ToLocal(&extendsFunc) || tc.HasCaught()) {
throw NativeScriptException(tc, "Cannot read '__extends' while loading " + modulePath);
}
thiz->Set(context, extendsName, extendsFunc);
moduleFunc->Call(context, thiz, sizeof(requireArgs) / sizeof(Local<Value> ), requireArgs);

if (tc.HasCaught()) {
Expand Down
13 changes: 12 additions & 1 deletion test-app/runtime/src/main/cpp/NativeScriptException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,19 @@ NativeScriptException::NativeScriptException(TryCatch& tc,
const string& message)
: m_javaException(JniLocalRef()) {
auto isolate = Isolate::GetCurrent();
m_javascriptException = new Persistent<Value>(isolate, tc.Exception());
auto ex = tc.Exception();
m_javascriptException =
ex.IsEmpty() ? nullptr : new Persistent<Value>(isolate, ex);

// A terminated isolate carries no message object and no inspectable
// exception - every accessor below hands back an empty handle. Resetting
// does not cancel the isolate's pending termination.
if (tc.HasTerminated() || tc.Message().IsEmpty()) {
m_message = message.empty() ? "Execution terminated." : message;
tc.Reset();
return;
}

m_message = GetErrorMessage(tc.Message(), ex, message);
m_stackTrace = GetErrorStackTrace(tc.Message()->GetStackTrace());
m_fullMessage = GetFullMessage(tc, m_message);
Expand Down
3 changes: 2 additions & 1 deletion test-app/runtime/src/main/cpp/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ void Runtime::Init(JavaVM* vm, void* reserved) {
// handle SIGABRT/SIGSEGV only on API level > 20 as the handling is not so
// efficient in older versions
if (m_androidVersion > 20) {
struct sigaction action;
struct sigaction action = {};
action.sa_handler = SIG_handler;
sigemptyset(&action.sa_mask);
sigaction(SIGABRT, &action, NULL);
sigaction(SIGSEGV, &action, NULL);
}
Expand Down