aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/zc0.c25
-rw-r--r--tests/programs/zc0embed_write.zc9
-rwxr-xr-xtests/test.sh1
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