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 "vector.h"
#include "regalloc.h"
#include "util.h"
#endif
/* Get a register */
@ -128,7 +129,8 @@ static void janetc_movenear(JanetCompiler *c,
((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) |
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,
((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) |
@ -155,6 +157,7 @@ static void janetc_moveback(JanetCompiler *c,
((uint32_t)(src) << 8) |
JOP_SET_UPVALUE);
} else if (dest.index != src) {
janet_assert(dest.index >= 0, "bad slot");
janetc_emit(c,
((uint32_t)(dest.index) << 16) |
((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) {
/* Closure body with return argument */
subopts.flags |= JANET_FOPTS_TAIL;
JanetSlot ret = janetc_value(subopts, argv[0]);
ret.flags |= JANET_SLOT_RETURNED;
return ret;
janetc_value(subopts, argv[0]);
return janetc_cslot(janet_wrap_nil());
} else {
/* while loop IIFE or no argument */
if (argn) {
@ -762,9 +761,7 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_value(subopts, argv[0]);
}
janetc_emit(c, JOP_RETURN_NIL);
JanetSlot s = janetc_cslot(janet_wrap_nil());
s.flags |= JANET_SLOT_RETURNED;
return s;
return janetc_cslot(janet_wrap_nil());
}
} else {
if (argn) {

View File

@ -924,4 +924,25 @@
[:strict 3 4 "bar-oops"]])
"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)