diff --git a/CHANGELOG.md b/CHANGELOG.md index 1422f95..5ce62e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,12 @@ * @Author: ekibun * @Date: 2020-08-08 08:16:50 * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 23:34:30 + * @LastEditTime: 2020-10-06 23:18:19 --> +## 0.1.3 + +* fix randomly crash by stack overflow. + ## 0.1.2 * fix qjs memory leak. diff --git a/cxx/ffi.cpp b/cxx/ffi.cpp index af3bf6c..f23f859 100644 --- a/cxx/ffi.cpp +++ b/cxx/ffi.cpp @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-09-06 18:32:45 * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 23:26:14 + * @LastEditTime: 2020-10-07 00:03:41 */ #include "ffi.h" #include @@ -100,6 +100,7 @@ extern "C" DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int32_t eval_flags) { + JS_ResetStackTop(JS_GetRuntime(ctx)); return new JSValue(JS_Eval(ctx, input, input_len, filename, eval_flags)); } @@ -196,6 +197,7 @@ extern "C" DLLEXPORT const char *jsToCString(JSContext *ctx, JSValueConst *val) { + JS_ResetStackTop(JS_GetRuntime(ctx)); return JS_ToCString(ctx, *val); } @@ -270,6 +272,7 @@ extern "C" DLLEXPORT JSValue *jsCall(JSContext *ctx, JSValueConst *func_obj, JSValueConst *this_obj, int32_t argc, JSValueConst *argv) { + JS_ResetStackTop(JS_GetRuntime(ctx)); return new JSValue(JS_Call(ctx, *func_obj, *this_obj, argc, argv)); } @@ -285,6 +288,7 @@ extern "C" DLLEXPORT int32_t jsExecutePendingJob(JSRuntime *rt) { + JS_ResetStackTop(rt); JSContext *ctx; return JS_ExecutePendingJob(rt, &ctx); } diff --git a/cxx/quickjs b/cxx/quickjs index 56cbb57..5e8a1f4 160000 --- a/cxx/quickjs +++ b/cxx/quickjs @@ -1 +1 @@ -Subproject commit 56cbb57a2e94a02a1bc2b2e75b15612c89fe324d +Subproject commit 5e8a1f421c00a8aa1d0af2dffd14b30d45832b83 diff --git a/example/pubspec.lock b/example/pubspec.lock index 312ef0c..681f5fa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -82,7 +82,7 @@ packages: path: ".." relative: true source: path - version: "0.1.2" + version: "0.1.3" flutter_test: dependency: "direct dev" description: flutter diff --git a/lib/ffi.dart b/lib/ffi.dart index 89677fb..3950114 100644 --- a/lib/ffi.dart +++ b/lib/ffi.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-09-19 10:29:04 * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 23:27:15 + * @LastEditTime: 2020-10-06 23:13:13 */ import 'dart:ffi'; import 'dart:io'; @@ -478,6 +478,7 @@ String jsToCString( Pointer val, ) { var ptr = _jsToCString(ctx, val); + if (ptr.address == 0) throw Exception("JSValue cannot convert to string"); var str = Utf8.fromUtf8(ptr); jsFreeCString(ctx, ptr); return str; diff --git a/lib/flutter_qjs.dart b/lib/flutter_qjs.dart index ddc0ac8..fb82f24 100644 --- a/lib/flutter_qjs.dart +++ b/lib/flutter_qjs.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-08-08 08:29:09 * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 21:55:07 + * @LastEditTime: 2020-10-06 23:47:13 */ import 'dart:async'; import 'dart:ffi'; @@ -121,6 +121,7 @@ class FlutterQjs { var jsval = jsEval(_ctx, command, name ?? "", evalFlags ?? JSEvalType.GLOBAL); if (jsIsException(jsval) != 0) { + jsFreeValue(_ctx, jsval); throw Exception(parseJSException(_ctx)); } var ret = runtimeOpaques[_rt]?.promsieToFuture(jsval); diff --git a/pubspec.yaml b/pubspec.yaml index 0537289..c44dee1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_qjs description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web! -version: 0.1.2 +version: 0.1.3 homepage: https://github.com/ekibun/flutter_qjs environment: diff --git a/test/flutter_qjs_test.dart b/test/flutter_qjs_test.dart index ef72181..48eff8c 100644 --- a/test/flutter_qjs_test.dart +++ b/test/flutter_qjs_test.dart @@ -3,16 +3,16 @@ * @Author: ekibun * @Date: 2020-09-06 13:02:46 * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 21:36:06 + * @LastEditTime: 2020-10-07 00:11:27 */ import 'dart:convert'; import 'dart:io'; +import 'package:flutter_qjs/flutter_qjs.dart'; import 'package:flutter_qjs/isolate.dart'; import 'package:flutter_test/flutter_test.dart'; dynamic myMethodHandler(method, args) { - print([method, args]); return args; } @@ -57,7 +57,6 @@ void main() async { test('jsToDart', () async { final qjs = IsolateQjs(myMethodHandler); qjs.setModuleHandler((name) async { - print(name); return "export default '${new DateTime.now()}'"; }); var value = await qjs.evaluate(""" @@ -68,8 +67,19 @@ void main() async { 0.1, true, false, 1, "world", module ])); """, name: ""); - print(value); - print(await value[0]('world')); + expect(value[1]['a'], value[1], reason: "recursive object"); + expect(await value[0]('world'), 'hello world!', reason: "js function call"); + qjs.close(); + }); + test('stack overflow', () async { + final qjs = FlutterQjs(); + try { + await qjs.evaluate("a=()=>a();a();", name: ""); + } catch (e) { + expect( + e.toString(), startsWith('Exception: InternalError: stack overflow'), + reason: "throw stack overflow"); + } qjs.close(); }); }