[master] ed36b6389 Defer the illegal write check a bit
Dridi Boukelmoune
dridi.boukelmoune at gmail.com
Wed Apr 1 07:49:08 UTC 2020
commit ed36b6389f9dbf6962e726f0df34d59132d9241a
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date: Wed Dec 18 18:14:59 2019 +0100
Defer the illegal write check a bit
After the initial discussion from #3163, and looking more closely at how
variable access is handled in subroutines I noticed a discrepancy.
Setting a read only variable like obj.ttl in vcl_recv would result in
a misleading error message explaining that it is read only, instead of
simply not available.
This change defers the illegal write check, registering unconditionally
that the symbol was used in a set action. As a result we always get the
correct error message but depending on whether this is happening in a
vcl_ or custom subroutine we may either get "in subroutine" or "from
subroutine" in the error message. A minor discrepancy probably worth
getting rid of the prior inconsistency.
This is covered by the v21 test case.
diff --git a/bin/varnishtest/tests/v00021.vtc b/bin/varnishtest/tests/v00021.vtc
index dd3392ee8..ab0618f98 100644
--- a/bin/varnishtest/tests/v00021.vtc
+++ b/bin/varnishtest/tests/v00021.vtc
@@ -2,14 +2,26 @@ varnishtest "VCL compiler coverage test: vcc_xref.c vcc_var.c vcc_symb.c"
varnish v1 -errvcl {Variable is read only.} {
backend b { .host = "127.0.0.1"; }
- sub vcl_recv { set obj.ttl = 1 w; }
+ sub vcl_deliver { set obj.ttl = 1 w; }
}
varnish v1 -errvcl {Variable is read only.} {
backend b { .host = "127.0.0.1"; }
sub foo { set obj.ttl = 1 w; }
- sub vcl_recv { call foo ; }
+ sub vcl_deliver { call foo; }
+}
+
+varnish v1 -errvcl {Not available in subroutine 'vcl_recv'.} {
+ backend b { .host = "127.0.0.1"; }
+ sub vcl_recv { set obj.ttl = 1 w; }
+}
+
+varnish v1 -errvcl {Not available from subroutine 'vcl_recv'.} {
+ backend b { .host = "127.0.0.1"; }
+
+ sub foo { set obj.ttl = 1 w; }
+ sub vcl_recv { call foo; }
}
varnish v1 -errvcl "Symbol not found" {
diff --git a/lib/libvcc/vcc_action.c b/lib/libvcc/vcc_action.c
index bcbeea9ba..8fa48b37c 100644
--- a/lib/libvcc/vcc_action.c
+++ b/lib/libvcc/vcc_action.c
@@ -127,15 +127,8 @@ vcc_act_set(struct vcc *tl, struct token *t, struct symbol *sym)
sym = VCC_SymbolGet(tl, SYM_VAR, SYMTAB_EXISTING, XREF_NONE);
ERRCHK(tl);
AN(sym);
- if (sym->w_methods == 0) {
- vcc_ErrWhere2(tl, t, tl->t);
- if (sym->r_methods != 0)
- VSB_printf(tl->sb, "Variable is read only.\n");
- else
- VSB_printf(tl->sb, "Variable cannot be set.\n");
- return;
- }
vcc_AddUses(tl, t, tl->t, sym, XREF_WRITE);
+ ERRCHK(tl);
type = sym->type;
for (ap = assign; ap->type != VOID; ap++) {
if (ap->type != type)
diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c
index d2e933db3..eff883274 100644
--- a/lib/libvcc/vcc_xref.c
+++ b/lib/libvcc/vcc_xref.c
@@ -139,6 +139,9 @@ vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
WRONG("wrong xref use");
VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
+
+ if (pu->mask == 0)
+ vcc_CheckUses(tl);
}
void
@@ -251,13 +254,40 @@ vcc_CheckAction(struct vcc *tl)
/*--------------------------------------------------------------------*/
static struct procuse *
-vcc_FindIllegalUse(const struct proc *p, const struct method *m)
+vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
{
- struct procuse *pu;
- VTAILQ_FOREACH(pu, &p->uses, list)
+ if (pu->mask || pu->use != XREF_WRITE)
+ return (NULL);
+
+ if (pu->sym->r_methods == 0) {
+ vcc_ErrWhere2(tl, pu->t1, pu->t2);
+ VSB_printf(tl->sb, "Variable cannot be set.\n");
+ return (NULL);
+ }
+
+ if (!(pu->sym->r_methods & m->bitval)) {
+ pu->use = XREF_READ; /* NB: change the error message. */
+ return (pu);
+ }
+
+ vcc_ErrWhere2(tl, pu->t1, pu->t2);
+ VSB_printf(tl->sb, "Variable is read only.\n");
+ return (NULL);
+}
+
+static struct procuse *
+vcc_FindIllegalUse(struct vcc *tl, const struct proc *p, const struct method *m)
+{
+ struct procuse *pu, *pw;
+
+ VTAILQ_FOREACH(pu, &p->uses, list) {
+ pw = vcc_illegal_write(tl, pu, m);
+ if (tl->err)
+ return (pw);
if (!(pu->mask & m->bitval))
return (pu);
+ }
return (NULL);
}
@@ -268,7 +298,7 @@ vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
struct proccall *pc;
struct procuse *pu;
- pu = vcc_FindIllegalUse(p, m);
+ pu = vcc_FindIllegalUse(tl, p, m);
if (pu != NULL) {
vcc_ErrWhere2(tl, pu->t1, pu->t2);
VSB_printf(tl->sb, "%s from subroutine '%s'.\n",
@@ -278,6 +308,8 @@ vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
vcc_ErrWhere(tl, p->name);
return (1);
}
+ if (tl->err)
+ return (1);
VTAILQ_FOREACH(pc, &p->calls, list) {
if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
@@ -299,7 +331,7 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym)
AN(p);
if (p->method == NULL)
return;
- pu = vcc_FindIllegalUse(p, p->method);
+ pu = vcc_FindIllegalUse(tl, p, p->method);
if (pu != NULL) {
vcc_ErrWhere2(tl, pu->t1, pu->t2);
VSB_printf(tl->sb, "%s in subroutine '%.*s'.",
@@ -307,6 +339,7 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym)
VSB_cat(tl->sb, "\nAt: ");
return;
}
+ ERRCHK(tl);
if (vcc_CheckUseRecurse(tl, p, p->method)) {
VSB_printf(tl->sb,
"\n...which is the \"%s\" subroutine\n", p->method->name);
More information about the varnish-commit
mailing list