From 6d2a164ddce6a80fd85e0cb8683bcb9d5b36e00b Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sat, 19 Dec 2015 22:40:09 +0200 Subject: [PATCH 1/2] Testcase for string replace() bug (GH-492) --- .../test-bug-string-replace-assert-gh492.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/ecmascript/test-bug-string-replace-assert-gh492.js diff --git a/tests/ecmascript/test-bug-string-replace-assert-gh492.js b/tests/ecmascript/test-bug-string-replace-assert-gh492.js new file mode 100644 index 00000000..e128f75a --- /dev/null +++ b/tests/ecmascript/test-bug-string-replace-assert-gh492.js @@ -0,0 +1,32 @@ +/* + * https://github.com/svaarala/duktape/issues/492 + */ + +/*=== +undefined +still here +undefinedfoo +still here +string "" +===*/ + +function test() { + // Caused an assert failure in Duktape 1.3.0 and prior, and with asserts + // disabled memory unsafe behavior. + print(String.prototype.replace(RegExp.prototype)); + print('still here'); + + // Similar case + print('foo'.replace(RegExp.prototype)); + print('still here'); + + // Ensure RegExp.prototype matches correctly (it's a RegExp instance too). + var m = RegExp.prototype.exec('foo'); + print(typeof m[0], JSON.stringify(m[0])); +} + +try { + test(); +} catch (e) { + print(e.stack || e); +} From c1a95a6557820666e66d9b6ccdc4ddd0c0e2854a Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sat, 19 Dec 2015 22:40:29 +0200 Subject: [PATCH 2/2] Add 0th capture to RegExp.prototype bytecode The bytecode was missing DUK_REOP_SAVE for indices 0 and 1, i.e. the zeroth capture, which caused the RegExp.prototype to match an empty input but without providing the zeroth capture which is assumed in other parts of Duktape internals. This caused the GH-492 assert failure and, with asserts disabled, a segfault. --- src/genbuiltins.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/genbuiltins.py b/src/genbuiltins.py index 7885bff3..fc1948a4 100644 --- a/src/genbuiltins.py +++ b/src/genbuiltins.py @@ -753,7 +753,7 @@ bi_regexp_prototype = { # RegExp internal value should match that of new RegExp() (E5 Sections 15.10.6 # and 15.10.7), i.e. a bytecode sequence that matches an empty string. # The compiled regexp bytecode for that is embedded here, and must match the - # defines in duk_regexp.h. + # defines in duk_regexp.h. The bytecode must provide the 0'th capture. # # Note that the property attributes are non-default. @@ -762,6 +762,10 @@ bi_regexp_prototype = { 'name': internal('Bytecode'), 'value': unichr(0) + # flags (none) unichr(2) + # nsaved == 2 + unichr(11) + # DUK_REOP_SAVE + unichr(0) + # 0 + unichr(11) + # DUK_REOP_SAVE + unichr(1) + # 1 unichr(1), # DUK_REOP_MATCH 'attributes': '', },