diff options
author | Petr Štetiar <ynezz@true.cz> | 2021-03-19 16:54:55 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-04-23 00:42:30 +0200 |
commit | 2b59097c3f61fa901e91ac4cea48940760439578 (patch) | |
tree | 958d739a78f959dfcd55b3d76e6e970ca53fa1c6 /tests/custom/03_bugs | |
parent | 80393611fb6634abcc0da1dee2da7c4418dbde8d (diff) |
tests: create custom tests from current tests cases
Signed-off-by: Petr Štetiar <ynezz@true.cz>
Diffstat (limited to 'tests/custom/03_bugs')
-rw-r--r-- | tests/custom/03_bugs/01_try_catch_stack_mismatch | 52 | ||||
-rw-r--r-- | tests/custom/03_bugs/02_array_pop_use_after_free | 14 | ||||
-rw-r--r-- | tests/custom/03_bugs/03_switch_fallthrough_miscompilation | 16 | ||||
-rw-r--r-- | tests/custom/03_bugs/04_property_set_abort | 76 | ||||
-rw-r--r-- | tests/custom/03_bugs/05_duplicate_ressource_type | 31 | ||||
-rw-r--r-- | tests/custom/03_bugs/06_lexer_escape_at_boundary | 12 | ||||
-rw-r--r-- | tests/custom/03_bugs/07_lexer_overlong_lines | 13 | ||||
-rw-r--r-- | tests/custom/03_bugs/08_compiler_arrow_fn_expressions | 15 | ||||
-rw-r--r-- | tests/custom/03_bugs/09_reject_invalid_array_indexes | 25 | ||||
-rw-r--r-- | tests/custom/03_bugs/10_break_stack_mismatch | 38 | ||||
-rw-r--r-- | tests/custom/03_bugs/11_switch_stack_mismatch | 39 | ||||
-rw-r--r-- | tests/custom/03_bugs/12_altblock_stack_mismatch | 83 |
12 files changed, 414 insertions, 0 deletions
diff --git a/tests/custom/03_bugs/01_try_catch_stack_mismatch b/tests/custom/03_bugs/01_try_catch_stack_mismatch new file mode 100644 index 0000000..f6e5a0a --- /dev/null +++ b/tests/custom/03_bugs/01_try_catch_stack_mismatch @@ -0,0 +1,52 @@ +When compiling a try/catch statement with an exception variable, the catch +skip jump incorrectly pointed to the POP instruction popping the exception +variable off the stack, leading to a stack position mismatch between +compiler and vm, causing local variables to yield wrong values at runtime. + +-- Expect stdout -- +1 +-- End -- + +-- Testcase -- +{% + function f() { + let x; + + try { + x = 1; + } + catch(e) { + + } + + // Before the fix, `x` incorrectly yielded the print function value + print(x, "\n"); + } + + f() +%} +-- End -- + + +When compiling a try/catch statement with local variable declearations +within the try block, the catch skip jump incorrectly happened before the +local try block variables were popped off the stack, leading to a stack +position mismatch between compiler and vm, causing local variables to +yield wrong values at runtime. + +-- Expect stdout -- +1 +-- End -- + +-- Testcase -- +{% + try { + let a; + } + catch {} + + let b = 1; + + print(b, "\n"); +%} +-- End -- diff --git a/tests/custom/03_bugs/02_array_pop_use_after_free b/tests/custom/03_bugs/02_array_pop_use_after_free new file mode 100644 index 0000000..22f63ff --- /dev/null +++ b/tests/custom/03_bugs/02_array_pop_use_after_free @@ -0,0 +1,14 @@ +When popping an element off an array, especially the last one, the popped +value might have been freed before the refcount was increased later on +function return. + +-- Expect stdout -- +1 +-- End -- + +-- Testcase -- +{% + x = [1]; + print(pop(x), "\n"); // This caused a SIGABRT before the bugfix +%} +-- End -- diff --git a/tests/custom/03_bugs/03_switch_fallthrough_miscompilation b/tests/custom/03_bugs/03_switch_fallthrough_miscompilation new file mode 100644 index 0000000..3e6410e --- /dev/null +++ b/tests/custom/03_bugs/03_switch_fallthrough_miscompilation @@ -0,0 +1,16 @@ +When falling through from a matched switch case into the default case, +the compiler incorrectly emitted bytecode that led to an endless loop. + +-- Expect stdout -- +1 +-- End -- + +-- Testcase -- +{% + switch (1) { + case 1: + default: + print("1\n"); + } +%} +-- End -- diff --git a/tests/custom/03_bugs/04_property_set_abort b/tests/custom/03_bugs/04_property_set_abort new file mode 100644 index 0000000..8af477f --- /dev/null +++ b/tests/custom/03_bugs/04_property_set_abort @@ -0,0 +1,76 @@ +When attempting to set a property on a non-array, non-object value the +VM aborted due to an assert triggered by libjson-c. + +-- Testcase -- +{% (null).x = 1 %} +-- End -- + +-- Expect stderr -- +Type error: attempt to set property on null value +In line 1, byte 15: + + `{% (null).x = 1 %}` + Near here ----^ + + +-- End -- + + +-- Testcase -- +{% (1).x = 1 %} +-- End -- + +-- Expect stderr -- +Type error: attempt to set property on integer value +In line 1, byte 12: + + `{% (1).x = 1 %}` + Near here -^ + + +-- End -- + + +-- Testcase -- +{% (1.2).x = 1 %} +-- End -- + +-- Expect stderr -- +Type error: attempt to set property on double value +In line 1, byte 14: + + `{% (1.2).x = 1 %}` + Near here ---^ + + +-- End -- + + +-- Testcase -- +{% (true).x = 1 %} +-- End -- + +-- Expect stderr -- +Type error: attempt to set property on boolean value +In line 1, byte 15: + + `{% (true).x = 1 %}` + Near here ----^ + + +-- End -- + + +-- Testcase -- +{% ("test").x = 1 %} +-- End -- + +-- Expect stderr -- +Type error: attempt to set property on string value +In line 1, byte 17: + + `{% ("test").x = 1 %}` + Near here ------^ + + +-- End -- diff --git a/tests/custom/03_bugs/05_duplicate_ressource_type b/tests/custom/03_bugs/05_duplicate_ressource_type new file mode 100644 index 0000000..21166b2 --- /dev/null +++ b/tests/custom/03_bugs/05_duplicate_ressource_type @@ -0,0 +1,31 @@ +When requiring a C module that registers custom ressource types multiple +times, ressource values instantiated after subsequent requires of the +same extensions didn't properly function since the internal type prototype +was resolved to the initial copy and subsequently discarded due to an index +mismatch. + +-- Testcase -- +{% + fs = require("fs"); + fd = fs.open("README.md"); + + printf("fd.read() #1: %s\n", + fd.read("line") ? "working" : "not working (" + fd.error() + ")"); + + fd.close(); + + + fs = require("fs"); + fd = fs.open("README.md"); + + printf("fd.read() #2: %s\n", + fd.read("line") ? "working" : "not working (" + fd.error() + ")"); + + fd.close(); +%} +-- End -- + +-- Expect stdout -- +fd.read() #1: working +fd.read() #2: working +-- End -- diff --git a/tests/custom/03_bugs/06_lexer_escape_at_boundary b/tests/custom/03_bugs/06_lexer_escape_at_boundary new file mode 100644 index 0000000..e80b0a1 --- /dev/null +++ b/tests/custom/03_bugs/06_lexer_escape_at_boundary @@ -0,0 +1,12 @@ +When the lexer processed a backslash introducing a string escape directly +at the buffer boundary, the backslash was incorrectly retained. + +-- Testcase -- +{% + print("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl\n"); +%} +-- End -- + +-- Expect stdout -- +abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +-- End -- diff --git a/tests/custom/03_bugs/07_lexer_overlong_lines b/tests/custom/03_bugs/07_lexer_overlong_lines new file mode 100644 index 0000000..d2dd3be --- /dev/null +++ b/tests/custom/03_bugs/07_lexer_overlong_lines @@ -0,0 +1,13 @@ +A logic flaw in the lineinfo encoding function led to an endless tight +loop when a buffer chunk with 128 byte got consumed, which may happen +when parsing very long literals. + +-- Testcase -- +{% + print("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg\n"); +%} +-- End -- + +-- Expect stdout -- +abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +-- End -- diff --git a/tests/custom/03_bugs/08_compiler_arrow_fn_expressions b/tests/custom/03_bugs/08_compiler_arrow_fn_expressions new file mode 100644 index 0000000..5cd8960 --- /dev/null +++ b/tests/custom/03_bugs/08_compiler_arrow_fn_expressions @@ -0,0 +1,15 @@ +Arrow functions with single expression bodies were parsed with a wrong +precedence level, causing comma expressions to be greedily consumed. + +-- Testcase -- +{% + print({ + a: () => 1, + b: () => 2 + }, "\n"); +%} +-- End -- + +-- Expect stdout -- +{ "a": "() => { ... }", "b": "() => { ... }" } +-- End -- diff --git a/tests/custom/03_bugs/09_reject_invalid_array_indexes b/tests/custom/03_bugs/09_reject_invalid_array_indexes new file mode 100644 index 0000000..a7e5272 --- /dev/null +++ b/tests/custom/03_bugs/09_reject_invalid_array_indexes @@ -0,0 +1,25 @@ +Since libjson-c's json_object_get_int64() returns 0 for any input value +that has no integer representation, any kind of invalid array index +incorrectly yielded the first array element. + +-- Testcase -- +{% + x = [1, 2, 3]; + + print([ + x[1], + x["1"], + x[1.0], + x[1.1], + x.foo, + x["foo"], + x["0abc"], + x[x], + x[{ foo: true }] + ], "\n"); +%} +-- End -- + +-- Expect stdout -- +[ 2, 2, 2, null, null, null, null, null, null ] +-- End -- diff --git a/tests/custom/03_bugs/10_break_stack_mismatch b/tests/custom/03_bugs/10_break_stack_mismatch new file mode 100644 index 0000000..ae16dac --- /dev/null +++ b/tests/custom/03_bugs/10_break_stack_mismatch @@ -0,0 +1,38 @@ +When emitting jump instructions for breaking out of for-loops, the compiler +incorrectly set the jump target before the pop instruction clearing the +intermediate loop variables. Since the break instruction itself already +compiles to a series of pop instructions reverting the stack to it's the +pre-loop state, intermediate values got popped twice, leading to a stack +layout mismatch between compiler and VM, resulting in wrong local variable +values or segmentation faults at runtime. + +-- Testcase -- +{% + let x = 1; + + for (let y in [2]) + break; + + print(x, "\n"); +%} +-- End -- + +-- Expect stdout -- +1 +-- End -- + + +-- Testcase -- +{% + let x = 1; + + for (let y = 0; y < 1; y++) + break; + + print(x, "\n"); +%} +-- End -- + +-- Expect stdout -- +1 +-- End -- diff --git a/tests/custom/03_bugs/11_switch_stack_mismatch b/tests/custom/03_bugs/11_switch_stack_mismatch new file mode 100644 index 0000000..cc3b41a --- /dev/null +++ b/tests/custom/03_bugs/11_switch_stack_mismatch @@ -0,0 +1,39 @@ +When jumping into a case following prior cases declaring local variables, +the preceding local variable declarations were skipped, leading to an +unexpected stack layout which caused local variables to carry wrong +values at run time and eventual segmentation faults when attempting to +unwind the stack on leaving the lexical switch scope. + +-- Expect stdout -- +Matching 1: + - 1: [ null, null, 3, 4 ] + - 2: [ null, null, 3, 4, 5, 6 ] +Matching 2: + - 2: [ null, null, null, null, 5, 6 ] +Matching 3: + - default: [ 1, 2 ] + - 1: [ 1, 2, 3, 4 ] + - 2: [ 1, 2, 3, 4, 5, 6 ] +-- End -- + +-- Testcase -- +{% + for (let n in [1, 2, 3]) { + printf("Matching %d:\n", n); + + switch (n) { + default: + let x = 1, y = 2; + print(" - default: ", [x, y], "\n"); + + case 1: + let a = 3, b = 4; + print(" - 1: ", [x, y, a, b], "\n"); + + case 2: + let c = 5, d = 6; + print(" - 2: ", [x, y, a, b, c, d], "\n"); + } + } +%} +-- End -- diff --git a/tests/custom/03_bugs/12_altblock_stack_mismatch b/tests/custom/03_bugs/12_altblock_stack_mismatch new file mode 100644 index 0000000..e350660 --- /dev/null +++ b/tests/custom/03_bugs/12_altblock_stack_mismatch @@ -0,0 +1,83 @@ +When compiling alternative syntax blocks, such as `for ...: endfor`, +`if ...: endif` etc., the compiler didn't assign the contained statements +to a dedicated lexical scope, which caused a stack mismatch between +compiler and vm when such blocks declaring local variables weren't +actually executed. + +-- Expect stdout -- +2 +-- End -- + +-- Testcase -- +{% + if (false): + let a = 1; + endif; + + /* Due to lack of own lexical scope above, the compiler assumed + * that `a` is still on stack but the code to initialize it was + * never executed, so stack offsets were shifted by one from here + * on throughout the rest of the program. */ + + let b = 2; + + print(b, "\n"); +%} +-- End -- + + +Test a variation of the bug using `for in..endfor` loop syntax. + +-- Expect stdout -- +2 +-- End -- + +-- Testcase -- +{% + for (let x in []): + let a = 1; + endfor; + + let b = 2; + + print(b, "\n"); +%} +-- End -- + + +Test a variation of the bug using `for..endfor` count loop syntax. + +-- Expect stdout -- +2 +-- End -- + +-- Testcase -- +{% + for (let i = 0; i < 0; i++): + let a = 1; + endfor; + + let b = 2; + + print(b, "\n"); +%} +-- End -- + + +Test a variation of the bug using `while..endwhile` loop syntax. + +-- Expect stdout -- +2 +-- End -- + +-- Testcase -- +{% + while (false): + let a = 1; + endwhile; + + let b = 2; + + print(b, "\n"); +%} +-- End -- |