From: phk Date: Mon, 25 Jun 2007 08:17:25 +0000 (+0000) Subject: Make the VCL compiler complain about attempts to access variables outside X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=57fa7ce2705aea02111addbf477631cd0ea253f1;p=varnish Make the VCL compiler complain about attempts to access variables outside their scope. One example of this is the "req.hash" variable which only exists in the vcl_hash method. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1552 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/include/vrt_obj.h b/varnish-cache/include/vrt_obj.h index 2208da7a..a1264299 100644 --- a/varnish-cache/include/vrt_obj.h +++ b/varnish-cache/include/vrt_obj.h @@ -26,6 +26,8 @@ const char * VRT_r_req_proto(struct sess *); void VRT_l_req_proto(struct sess *, const char *); struct backend * VRT_r_req_backend(struct sess *); void VRT_l_req_backend(struct sess *, struct backend *); +const char * VRT_r_req_http_(struct sess *); +void VRT_l_req_http_(struct sess *, const char *); const char * VRT_r_req_hash(struct sess *); void VRT_l_req_hash(struct sess *, const char *); unsigned VRT_r_obj_valid(struct sess *); @@ -34,7 +36,5 @@ unsigned VRT_r_obj_cacheable(struct sess *); void VRT_l_obj_cacheable(struct sess *, unsigned); double VRT_r_obj_ttl(struct sess *); void VRT_l_obj_ttl(struct sess *, double); -const char * VRT_r_req_http_(struct sess *); -void VRT_l_req_http_(struct sess *, const char *); const char * VRT_r_resp_http_(struct sess *); void VRT_l_resp_http_(struct sess *, const char *); diff --git a/varnish-cache/lib/libvcl/vcc_compile.c b/varnish-cache/lib/libvcl/vcc_compile.c index b8aed639..59e5f76a 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.c +++ b/varnish-cache/lib/libvcl/vcc_compile.c @@ -82,7 +82,7 @@ struct method method_tab[] = { #define VCL_RET_MAC(l,U,b,n) -#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m }, +#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m, VCL_MET_##U }, #include "vcl_returns.h" #undef VCL_MET_MAC #undef VCL_RET_MAC @@ -278,6 +278,7 @@ FindVar(struct tokenlist *tl, const struct token *t, struct var *vl) continue; if (memcmp(t->b, v->name, v->len)) continue; + vcc_AddUses(tl, v); if (v->fmt != HEADER) return (v); return (HeaderVar(tl, t, v)); @@ -645,6 +646,11 @@ vcc_CompileSource(struct vsb *sb, struct source *sp) if (tl->err) return (vcc_DestroyTokenList(tl, NULL)); + /* Check that all variable uses are legal */ + vcc_CheckUses(tl); + if (tl->err) + return (vcc_DestroyTokenList(tl, NULL)); + Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); /* Emit method functions */ diff --git a/varnish-cache/lib/libvcl/vcc_compile.h b/varnish-cache/lib/libvcl/vcc_compile.h index d6ec1437..de769605 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.h +++ b/varnish-cache/lib/libvcl/vcc_compile.h @@ -127,10 +127,9 @@ struct var { struct method { const char *name; unsigned returns; + unsigned bitval; }; -struct proc; - /*--------------------------------------------------------------------*/ /* vcc_acl.c */ @@ -180,7 +179,7 @@ void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line); void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e); void vcc_FreeToken(struct token *t); -/* vcc_expr.c */ +/* vcc_xref.c */ void vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); void vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); int vcc_CheckReferences(struct tokenlist *tl); @@ -189,6 +188,8 @@ void vcc_AddCall(struct tokenlist *tl, struct token *t); struct proc *vcc_AddProc(struct tokenlist *tl, struct token *t); void vcc_ProcAction(struct proc *p, unsigned action, struct token *t); int vcc_CheckAction(struct tokenlist *tl); +void vcc_AddUses(struct tokenlist *tl, struct var *v); +int vcc_CheckUses(struct tokenlist *tl); #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__) diff --git a/varnish-cache/lib/libvcl/vcc_parse.c b/varnish-cache/lib/libvcl/vcc_parse.c index 522a6b16..91fa793a 100644 --- a/varnish-cache/lib/libvcl/vcc_parse.c +++ b/varnish-cache/lib/libvcl/vcc_parse.c @@ -545,6 +545,7 @@ Function(struct tokenlist *tl) tl->indent -= INDENT; Fb(tl, 0, "\n"); tl->fb = NULL; + tl->curproc = NULL; } /*-------------------------------------------------------------------- diff --git a/varnish-cache/lib/libvcl/vcc_xref.c b/varnish-cache/lib/libvcl/vcc_xref.c index 658287e7..9729cbf2 100644 --- a/varnish-cache/lib/libvcl/vcc_xref.c +++ b/varnish-cache/lib/libvcl/vcc_xref.c @@ -55,9 +55,16 @@ struct proccall { struct token *t; }; +struct procuse { + TAILQ_ENTRY(procuse) list; + struct token *t; + struct var *v; +}; + struct proc { TAILQ_ENTRY(proc) list; TAILQ_HEAD(,proccall) calls; + TAILQ_HEAD(,procuse) uses; struct token *name; unsigned returns; unsigned exists; @@ -180,6 +187,7 @@ vcc_findproc(struct tokenlist *tl, struct token *t) p = TlAlloc(tl, sizeof *p); assert(p != NULL); TAILQ_INIT(&p->calls); + TAILQ_INIT(&p->uses); TAILQ_INSERT_TAIL(&tl->procs, p, list); p->name = t; return (p); @@ -196,6 +204,20 @@ vcc_AddProc(struct tokenlist *tl, struct token *t) return (p); } +void +vcc_AddUses(struct tokenlist *tl, struct var *v) +{ + struct procuse *pu; + + if (tl->curproc == NULL) /* backend */ + return; + pu = TlAlloc(tl, sizeof *pu); + assert(pu != NULL); + pu->v = v; + pu->t = tl->t; + TAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list); +} + void vcc_AddCall(struct tokenlist *tl, struct token *t) { @@ -305,3 +327,73 @@ vcc_CheckAction(struct tokenlist *tl) return (0); } +static struct procuse * +vcc_FindIllegalUse(struct proc *p, struct method *m) +{ + struct procuse *pu; + + TAILQ_FOREACH(pu, &p->uses, list) + if (!(pu->v->methods & m->bitval)) + return (pu); + return (NULL); +} + +static int +vcc_CheckUseRecurse(struct tokenlist *tl, struct proc *p, struct method *m) +{ + struct proccall *pc; + struct procuse *pu; + + pu = vcc_FindIllegalUse(p, m); + if (pu != NULL) { + vsb_printf(tl->sb, + "Variable \"%.*s\" is not available in %s\n", + PF(pu->t), m->name); + vcc_ErrWhere(tl, pu->t); + vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", + PF(p->name)); + vcc_ErrWhere(tl, p->name); + return (1); + } + TAILQ_FOREACH(pc, &p->calls, list) { + if (vcc_CheckUseRecurse(tl, pc->p, m)) { + vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", + PF(p->name)); + vcc_ErrWhere(tl, pc->t); + return (1); + } + } + return (0); +} + +int +vcc_CheckUses(struct tokenlist *tl) +{ + struct proc *p; + struct method *m; + struct procuse *pu; + int i; + + TAILQ_FOREACH(p, &tl->procs, list) { + i = IsMethod(p->name); + if (i < 0) + continue; + m = method_tab + i; + pu = vcc_FindIllegalUse(p, m); + if (pu != NULL) { + vsb_printf(tl->sb, + "Variable '%.*s' not accessible in method '%.*s'.", + PF(pu->t), PF(p->name)); + vsb_cat(tl->sb, "\nAt: "); + vcc_ErrWhere(tl, pu->t); + return (1); + } + if (vcc_CheckUseRecurse(tl, p, m)) { + vsb_printf(tl->sb, + "\n...which is the \"%s\" method\n", m->name); + return (1); + } + } + return (0); +} +