diff options
| author | 2026-10-14 16:40:29 +0330 | |
|---|---|---|
| committer | 2026-10-14 16:40:29 +0330 | |
| commit | 353e31c2648cc4248108091b29f97b9aa3204cba (patch) | |
| tree | 9e2b55948a24c9fc5a28ee05a735886185a69c83 | |
| parent | zc0: free the saved token when the local-embed lookahead returns early (diff) | |
zc0: a store into a local embed array is an error (its elements are in the code); test in tests/test.sh
| -rw-r--r-- | src/tools/zc0.c | 25 | ||||
| -rw-r--r-- | tests/programs/zc0embed_write.zc | 9 | ||||
| -rwxr-xr-x | tests/test.sh | 1 |
3 files changed, 27 insertions, 8 deletions
diff --git a/src/tools/zc0.c b/src/tools/zc0.c index d484016..6c62abf 100644 --- a/src/tools/zc0.c +++ b/src/tools/zc0.c @@ -48,6 +48,9 @@ static void tsroom(size_t n) ts = nb; tscap = c; } static int xf, xs, lvi; /* float, byte string; the plain local it came from, or -1 */ +/* xro: the value is a local embed array (Loc.ro); lro: the lvalue is one of its elements, which zc0 refuses to write */ +static int xro, lro; +static void rocheck(void); static int64_t *img; static int imgcap, here = GORG; static void emit(int64_t w) { @@ -296,7 +299,7 @@ static void fnref(const char *n) /* push a function address, fixing it up later } /* ---- locals ---- */ -typedef struct { char name[64]; int slot, arr, flt, str, dstr; } Loc; /* dstr: declared bstr, so always a byte string */ +typedef struct { char name[64]; int slot, arr, flt, str, dstr, ro; } Loc; /* dstr: declared bstr, so always a byte string; ro: a local embed array, whose elements are in the code */ static Loc lo[1024]; static int nlo, nslot, infn; static Loc *findl(const char *n) { int i; for (i = nlo; i--;) if (!strcmp(lo[i].name, n)) return &lo[i]; return 0; } static int isrecast(void) @@ -597,10 +600,11 @@ static int returns_bstr(const char *n) } static int args(void) { int n = 0; expect("("); if (!accept(")")) { do { expr(); rval(); n++; } while (accept(",")); expect(")"); } return n; } static void asmblock(void); +static void rocheck(void) { if (lro) die("a local embed array is part of the code; zc0 does not let a program write it (embed it at the top level)"); } static void primary(void) { char n[64]; Loc *l; Sym *s; - lv = 0; lvi = -1; xf = 0; xs = 0; + lv = 0; lvi = -1; xf = 0; xs = 0; xro = 0; lro = 0; if (tk == T_FLT) { emit(1200); emit(tv); xf = 1; next(); return; } if (tk == T_NUM) { lit(tv); next(); return; } if (tk == T_BSTR) { bstrlit(); xs = 1; return; } @@ -608,7 +612,7 @@ static void primary(void) if (accept("(")) { expr(); expect(")"); return; } if (is("asm")) { next(); asmblock(); return; } strcpy(n, ident()); - if ((l = findl(n))) { laddr(l->slot); lv = !l->arr; if (!l->arr) { xf = l->flt; xs = l->str; lvi = (int)(l - lo); } return; } + if ((l = findl(n))) { laddr(l->slot); lv = !l->arr; if (!l->arr) { xf = l->flt; xs = l->str; lvi = (int)(l - lo); } xro = l->ro; return; } s = find(n); if (s && s->kind == K_CONST) { lit(s->val); return; } if (s && s->kind == K_GVAR) { lit(s->val); lv = 1; xs = s->str; return; } @@ -634,6 +638,7 @@ static void primary(void) static void incdec(int post, int d) { if (!lv) die("++/-- needs an lvalue"); + rocheck(); lv = 0; if (lvi >= 0) lo[lvi].str = lo[lvi].dstr; xs = 0; @@ -646,6 +651,7 @@ static void postfix(void) primary(); for (;;) { if (accept("[")) { + int ro = xro; was = xs; rval(); expr(); rval(); if (was && accept(":")) { expr(); rval(); expect("]"); fnref("slice_s"); op(O_CALL); @@ -654,8 +660,9 @@ static void postfix(void) expect("]"); fnref("at_s"); op(O_CALL); lv = 0; xs = 0; xf = 0; lvi = -1; } else { expect("]"); op(O_ADD); lv = 1; xs = 0; xf = 0; lvi = -1; } + xro = 0; lro = ro; } - else if (is("(")) { rval(); n = args(); lit(n); op(O_PICK); op(O_CALL); op(O_SWAP); op(O_DROP); xf = 0; xs = 0; lvi = -1; } + else if (is("(")) { rval(); n = args(); lit(n); op(O_PICK); op(O_CALL); op(O_SWAP); op(O_DROP); xf = 0; xs = 0; lvi = -1; xro = 0; lro = 0; } else if (accept("++")) incdec(1, 1); else if (accept("--")) incdec(1, -1); else if (accept("as")) ptype0(); /* the whole type, as the compiler reads it: x as int*, x as char** */ @@ -671,7 +678,7 @@ static void unary(void) } else if (accept("!")) { unary(); rval(); ftest(); seq_isz(); xf = 0; xs = 0; } else if (accept("~")) { unary(); rval(); lit(-1); op(O_XOR); xf = 0; xs = 0; } - else if (accept("*")) { unary(); rval(); lv = 1; xs = 0; } + else if (accept("*")) { unary(); rval(); lv = 1; xs = 0; xro = 0; lro = 0; } else if (accept("&")) { unary(); if (!lv) die("& needs an lvalue"); lv = 0; xs = 0; } else if (accept("++")) { unary(); incdec(0, 1); } else if (accept("--")) { unary(); incdec(0, -1); } @@ -698,7 +705,7 @@ static void bin(int minp) } else if ((lf || rf) && fis(o)) { fbinop(o, lf, rf); xs = 0; } else { binop(o); xf = 0; xs = 0; } } - lv = 0; lvi = -1; + lv = 0; lvi = -1; xro = 0; lro = 0; } } static void expr(void) @@ -707,11 +714,13 @@ static void expr(void) bin(1); dst = lvi; if (is("=")) { if (!lv) die("assignment needs an lvalue"); + rocheck(); next(); expr(); rval(); op(O_SWAP); lit(1); op(O_PICK); op(O_SWAP); op(O_ST); lv = 0; if (dst >= 0) { lo[dst].flt = xf; lo[dst].str = xs || lo[dst].dstr; } } else if (tk == T_OP && strlen(ts) >= 2 && ts[strlen(ts) - 1] == '=' && strcmp(ts, "==") && strcmp(ts, "!=") && strcmp(ts, "<=") && strcmp(ts, ">=")) { if (!lv) die("assignment needs an lvalue"); + rocheck(); lf = xf; strcpy(o, ts); o[strlen(o) - 1] = 0; next(); lit(0); op(O_PICK); op(O_LD); lv = 0; expr(); rval(); if ((lf || xf) && fis(o)) fbinop(o, lf, xf); @@ -956,7 +965,7 @@ static int embed_width(const char *t, int star) } static Loc *newloc(const char *n) { - Loc *l = &lo[nlo++]; strcpy(l->name, n); l->slot = nslot++; l->arr = l->flt = l->str = l->dstr = 0; + Loc *l = &lo[nlo++]; strcpy(l->name, n); l->slot = nslot++; l->arr = l->flt = l->str = l->dstr = l->ro = 0; return l; } static void embeddecl(int local) @@ -1031,7 +1040,7 @@ static void embeddecl(int local) emit((int64_t)u); } if (!count) emit(0); - if (local) { setlit(j, here); l = newloc(n); lit(a); laddr(l->slot); op(O_ST); } + if (local) { setlit(j, here); l = newloc(n); l->ro = 1; lit(a); laddr(l->slot); op(O_ST); } else add(n, K_GARR, a); } free(buf); diff --git a/tests/programs/zc0embed_write.zc b/tests/programs/zc0embed_write.zc new file mode 100644 index 0000000..09686b5 --- /dev/null +++ b/tests/programs/zc0embed_write.zc @@ -0,0 +1,9 @@ +include rt; +// zc0 keeps a local embed array in the code, so it refuses a store into one; the +// resident compiler accepts it (prints 9). tests/test.sh checks zc0's message. +fn main() { + embed "tests/data/embed/bytes.bin" as u8[] b; + b[1] = 9; + rt.put_n(b[1]); rt.put_c(10); + return 0; +} diff --git a/tests/test.sh b/tests/test.sh index 7a80c3c..5b62262 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -82,6 +82,7 @@ GI="-Isrc/core -I$MAP --embed-dir=$T/s1" # it, and the run-only and bare-metal sections read it as the reference. $CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zy || exit 1 chk "$($T/zc0 < tests/programs/zc0typed.zc | md5sum)" "$($T/zc0 < tests/programs/zc0plain.zc | md5sum)" "zc0 reads types and throws them away: typed and plain sources give one image" +case "$($T/zc0 < tests/programs/zc0embed_write.zc 2>&1 >/dev/null)" in *"line 6: a local embed array is part of the code"*) chk 1 1 "zc0 refuses a store into a local embed array";; *) chk 0 1 "zc0 refuses a store into a local embed array";; esac for n in $SECS; do mkdir -p $ROOT/$n |
