]> err.no Git - varnish/commitdiff
Make the VCL compiler complain about attempts to access variables outside
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Mon, 25 Jun 2007 08:17:25 +0000 (08:17 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Mon, 25 Jun 2007 08:17:25 +0000 (08:17 +0000)
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

varnish-cache/include/vrt_obj.h
varnish-cache/lib/libvcl/vcc_compile.c
varnish-cache/lib/libvcl/vcc_compile.h
varnish-cache/lib/libvcl/vcc_parse.c
varnish-cache/lib/libvcl/vcc_xref.c

index 2208da7a1d20c044541a26841fb8d007d596539e..a12642992dd7e7f80668b65acdcca509b8f99764 100644 (file)
@@ -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 *);
index b8aed639cccaaed7a652e479588ee2808aaa61de..59e5f76a0e1d192cd75c43f9f4c13c1f2118aa79 100644 (file)
@@ -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 */
index d6ec14370a9a4a0d1098ce78bdead33fa6d1b3ec..de76960524f6cc459cbc00fe3c5511745ba265c2 100644 (file)
@@ -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__)
index 522a6b16b351f2cd2c835cd5a829c8425e4e9fc7..91fa793a09d18f4f7d5a6ecbfb419844f90bc1a7 100644 (file)
@@ -545,6 +545,7 @@ Function(struct tokenlist *tl)
        tl->indent -= INDENT;
        Fb(tl, 0, "\n");
        tl->fb = NULL;
+       tl->curproc = NULL;
 }
 
 /*--------------------------------------------------------------------
index 658287e7b0d1931abf0123db933aa0e103b869b2..9729cbf266f430559c2c6a69f00c9f52d4c5fb96 100644 (file)
@@ -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);
+}
+