1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-08 13:02:55 +00:00

Address compiler bug with break.

Using result from `break` expression could trigger code that would
work, yet contain invalid, dead code preventing good marshalling.
This commit is contained in:
Calvin Rose 2023-09-28 20:14:22 -05:00
parent b63d41102e
commit e05bc7eb54
3 changed files with 28 additions and 7 deletions

View File

@ -26,6 +26,7 @@
#include "emit.h" #include "emit.h"
#include "vector.h" #include "vector.h"
#include "regalloc.h" #include "regalloc.h"
#include "util.h"
#endif #endif
/* Get a register */ /* Get a register */
@ -128,7 +129,8 @@ static void janetc_movenear(JanetCompiler *c,
((uint32_t)(src.envindex) << 16) | ((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) | ((uint32_t)(dest) << 8) |
JOP_LOAD_UPVALUE); JOP_LOAD_UPVALUE);
} else if (src.index > 0xFF || src.index != dest) { } else if (src.index != dest) {
janet_assert(src.index >= 0, "bad slot");
janetc_emit(c, janetc_emit(c,
((uint32_t)(src.index) << 16) | ((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) | ((uint32_t)(dest) << 8) |
@ -155,6 +157,7 @@ static void janetc_moveback(JanetCompiler *c,
((uint32_t)(src) << 8) | ((uint32_t)(src) << 8) |
JOP_SET_UPVALUE); JOP_SET_UPVALUE);
} else if (dest.index != src) { } else if (dest.index != src) {
janet_assert(dest.index >= 0, "bad slot");
janetc_emit(c, janetc_emit(c,
((uint32_t)(dest.index) << 16) | ((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) | ((uint32_t)(src) << 8) |

View File

@ -752,9 +752,8 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
if (!(scope->flags & JANET_SCOPE_WHILE) && argn) { if (!(scope->flags & JANET_SCOPE_WHILE) && argn) {
/* Closure body with return argument */ /* Closure body with return argument */
subopts.flags |= JANET_FOPTS_TAIL; subopts.flags |= JANET_FOPTS_TAIL;
JanetSlot ret = janetc_value(subopts, argv[0]); janetc_value(subopts, argv[0]);
ret.flags |= JANET_SLOT_RETURNED; return janetc_cslot(janet_wrap_nil());
return ret;
} else { } else {
/* while loop IIFE or no argument */ /* while loop IIFE or no argument */
if (argn) { if (argn) {
@ -762,9 +761,7 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_value(subopts, argv[0]); janetc_value(subopts, argv[0]);
} }
janetc_emit(c, JOP_RETURN_NIL); janetc_emit(c, JOP_RETURN_NIL);
JanetSlot s = janetc_cslot(janet_wrap_nil()); return janetc_cslot(janet_wrap_nil());
s.flags |= JANET_SLOT_RETURNED;
return s;
} }
} else { } else {
if (argn) { if (argn) {

View File

@ -924,4 +924,25 @@
[:strict 3 4 "bar-oops"]]) [:strict 3 4 "bar-oops"]])
"maclintf 2") "maclintf 2")
# Bad bytecode wrt. using result from break expression
(defn bytecode-roundtrip
[f]
(assert-no-error "bytecode round-trip" (unmarshal (marshal f make-image-dict))))
(defn case-1 [&] (def x (break 1)))
(bytecode-roundtrip case-1)
(defn foo [&])
(defn case-2 [&]
(foo (break (foo)))
(foo))
(bytecode-roundtrip case-2)
(defn case-3 [&]
(def x (break (do (foo)))))
(bytecode-roundtrip case-3)
# Debug bytecode of these functions
# (pp (disasm case-1))
# (pp (disasm case-2))
# (pp (disasm case-3))
(end-suite) (end-suite)