Mailing List Archive

r1552 - in trunk/varnish-cache: include lib/libvcl
Author: phk
Date: 2007-06-25 10:17:25 +0200 (Mon, 25 Jun 2007)
New Revision: 1552

Modified:
trunk/varnish-cache/include/vrt_obj.h
trunk/varnish-cache/lib/libvcl/vcc_compile.c
trunk/varnish-cache/lib/libvcl/vcc_compile.h
trunk/varnish-cache/lib/libvcl/vcc_parse.c
trunk/varnish-cache/lib/libvcl/vcc_xref.c
Log:
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.



Modified: trunk/varnish-cache/include/vrt_obj.h
===================================================================
--- trunk/varnish-cache/include/vrt_obj.h 2007-06-25 07:14:08 UTC (rev 1551)
+++ trunk/varnish-cache/include/vrt_obj.h 2007-06-25 08:17:25 UTC (rev 1552)
@@ -26,6 +26,8 @@
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 @@
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 *);

Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-06-25 07:14:08 UTC (rev 1551)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-06-25 08:17:25 UTC (rev 1552)
@@ -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 @@
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 @@
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 */

Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-06-25 07:14:08 UTC (rev 1551)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-06-25 08:17:25 UTC (rev 1552)
@@ -127,10 +127,9 @@
struct method {
const char *name;
unsigned returns;
+ unsigned bitval;
};

-struct proc;
-
/*--------------------------------------------------------------------*/

/* vcc_acl.c */
@@ -180,7 +179,7 @@
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 @@
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__)

Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-06-25 07:14:08 UTC (rev 1551)
+++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-06-25 08:17:25 UTC (rev 1552)
@@ -545,6 +545,7 @@
tl->indent -= INDENT;
Fb(tl, 0, "\n");
tl->fb = NULL;
+ tl->curproc = NULL;
}

/*--------------------------------------------------------------------

Modified: trunk/varnish-cache/lib/libvcl/vcc_xref.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_xref.c 2007-06-25 07:14:08 UTC (rev 1551)
+++ trunk/varnish-cache/lib/libvcl/vcc_xref.c 2007-06-25 08:17:25 UTC (rev 1552)
@@ -55,9 +55,16 @@
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 @@
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);
@@ -197,6 +205,20 @@
}

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)
{
struct proccall *pc;
@@ -305,3 +327,73 @@
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);
+}
+