summaryrefslogtreecommitdiffhomepage
path: root/tests/custom/03_bugs
diff options
context:
space:
mode:
authorPetr Štetiar <ynezz@true.cz>2021-03-19 16:54:55 +0100
committerJo-Philipp Wich <jo@mein.io>2021-04-23 00:42:30 +0200
commit2b59097c3f61fa901e91ac4cea48940760439578 (patch)
tree958d739a78f959dfcd55b3d76e6e970ca53fa1c6 /tests/custom/03_bugs
parent80393611fb6634abcc0da1dee2da7c4418dbde8d (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_mismatch52
-rw-r--r--tests/custom/03_bugs/02_array_pop_use_after_free14
-rw-r--r--tests/custom/03_bugs/03_switch_fallthrough_miscompilation16
-rw-r--r--tests/custom/03_bugs/04_property_set_abort76
-rw-r--r--tests/custom/03_bugs/05_duplicate_ressource_type31
-rw-r--r--tests/custom/03_bugs/06_lexer_escape_at_boundary12
-rw-r--r--tests/custom/03_bugs/07_lexer_overlong_lines13
-rw-r--r--tests/custom/03_bugs/08_compiler_arrow_fn_expressions15
-rw-r--r--tests/custom/03_bugs/09_reject_invalid_array_indexes25
-rw-r--r--tests/custom/03_bugs/10_break_stack_mismatch38
-rw-r--r--tests/custom/03_bugs/11_switch_stack_mismatch39
-rw-r--r--tests/custom/03_bugs/12_altblock_stack_mismatch83
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 --