[master] f03948f48 initialize PRIV_TASK and PRIV_TOP vmod arguments once per subroutine

Nils Goroll nils.goroll at uplex.de
Wed Aug 29 06:14:09 UTC 2018


commit f03948f48445be4dbea5f389ac4168b4a6befc6c
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Tue Aug 14 14:02:34 2018 +0200

    initialize PRIV_TASK and PRIV_TOP vmod arguments once per subroutine
    
    ... and fail the VCL unless successful.
    
    Providing the PRIVs to vmods is a core function, so error handling
    should happen outside vmods.
    
    Besides being safe, this initialization can be more efficient than
    previous code for PRIVs used frequently within the same subroutine.
    
    An alternative approach would be to initialize all privs once per
    task / top request, but unless all privs are actually used in a VCL,
    this approach could impose significant overhead, both in terms of time
    and memory. By initializing privs once per sub, we impose overhead for
    privs which are referenced but not actually used in a subroutine, but
    not for all of the vcl.
    
    Fixes #2708

diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c
index a7dfc98d3..1adc26721 100644
--- a/lib/libvcc/vcc_compile.c
+++ b/lib/libvcc/vcc_compile.c
@@ -104,6 +104,8 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym)
 	AN(p);
 	VTAILQ_INIT(&p->calls);
 	VTAILQ_INIT(&p->uses);
+	VTAILQ_INIT(&p->priv_tasks);
+	VTAILQ_INIT(&p->priv_tops);
 	VTAILQ_INSERT_TAIL(&tl->procs, p, list);
 	p->prologue = VSB_new_auto();
 	AN(p->prologue);
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index befc15a94..4e67b538c 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -174,6 +174,7 @@ struct symbol {
 };
 
 VTAILQ_HEAD(tokenhead, token);
+VTAILQ_HEAD(procprivhead, procpriv);
 
 struct proc {
 	unsigned		magic;
@@ -181,6 +182,8 @@ struct proc {
 	const struct method	*method;
 	VTAILQ_HEAD(,proccall)	calls;
 	VTAILQ_HEAD(,procuse)	uses;
+	struct procprivhead	priv_tasks;
+	struct procprivhead	priv_tops;
 	VTAILQ_ENTRY(proc)	list;
 	struct token		*name;
 	unsigned		ret_bitmap;
@@ -389,6 +392,8 @@ int vcc_CheckAction(struct vcc *tl);
 void vcc_AddUses(struct vcc *, const struct token *, const struct token *,
      unsigned mask, const char *use);
 int vcc_CheckUses(struct vcc *tl);
+const char *vcc_MarkPriv(struct vcc *, struct procprivhead *,
+    const char *);
 
 #define ERRCHK(tl)      do { if ((tl)->err) return; } while (0)
 #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index e016696a5..1f0699e19 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -399,31 +399,49 @@ vcc_Eval_Var(struct vcc *tl, struct expr **e, struct token *t,
  */
 
 static struct expr *
-vcc_priv_arg(struct vcc *tl, const char *p, const char *name, const char *vmod)
+vcc_priv_arg(struct vcc *tl, const char *p, const struct symbol *sym)
 {
-	struct expr *e2;
-	char buf[32];
+	char buf[64];
 	struct inifin *ifp;
+	const char *vmod, *f = NULL;
+	struct procprivhead *marklist = NULL;
+
+	AN(sym);
+	AN(sym->vmod);
+	vmod = sym->vmod;
 
-	(void)name;
 	if (!strcmp(p, "PRIV_VCL")) {
-		e2 = vcc_mk_expr(VOID, "&vmod_priv_%s", vmod);
+		return (vcc_mk_expr(VOID, "&vmod_priv_%s", vmod));
 	} else if (!strcmp(p, "PRIV_CALL")) {
 		bprintf(buf, "vmod_priv_%u", tl->unique++);
 		ifp = New_IniFin(tl);
 		Fh(tl, 0, "static struct vmod_priv %s;\n", buf);
 		VSB_printf(ifp->fin, "\tVRT_priv_fini(&%s);", buf);
-		e2 = vcc_mk_expr(VOID, "&%s", buf);
+		return (vcc_mk_expr(VOID, "&%s", buf));
 	} else if (!strcmp(p, "PRIV_TASK")) {
-		e2 = vcc_mk_expr(VOID,
-		    "VRT_priv_task(ctx, &VGC_vmod_%s)", vmod);
+		f = "task";
+		marklist = &tl->curproc->priv_tasks;
 	} else if (!strcmp(p, "PRIV_TOP")) {
-		e2 = vcc_mk_expr(VOID,
-		    "VRT_priv_top(ctx, &VGC_vmod_%s)", vmod);
+		f = "top";
+		marklist = &tl->curproc->priv_tops;
 	} else {
 		WRONG("Wrong PRIV_ type");
 	}
-	return (e2);
+	AN(f);
+	AN(marklist);
+	bprintf(buf, "ARG_priv_%s_%s", f, vmod);
+
+	if (vcc_MarkPriv(tl, marklist, vmod) == NULL)
+		VSB_printf(tl->curproc->prologue,
+			   "  struct vmod_priv *%s = "
+			   "VRT_priv_%s(ctx, &VGC_vmod_%s);\n"
+			   "  if (%s == NULL) {\n"
+			   "    VRT_fail(ctx, \"failed to get %s priv "
+			   "for vmod %s\");\n"
+			   "    return;\n"
+			   "  }\n",
+			   buf, f, vmod, buf, f, vmod);
+	return (vcc_mk_expr(VOID, "%s", buf));
 }
 
 struct func_arg {
@@ -522,8 +540,7 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
 
 		vvp = VTAILQ_FIRST(&vv->children);
 		if (!memcmp(vvp->value, "PRIV_", 5)) {
-			fa->result = vcc_priv_arg(tl, vvp->value,
-			    sym->name, sym->vmod);
+			fa->result = vcc_priv_arg(tl, vvp->value, sym);
 			continue;
 		}
 		fa->type = VCC_Type(vvp->value);
diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c
index 31d3bc6cd..bfa98a6f6 100644
--- a/lib/libvcc/vcc_xref.c
+++ b/lib/libvcc/vcc_xref.c
@@ -39,6 +39,7 @@
 
 #include "config.h"
 
+#include <string.h>
 #include "vcc_compile.h"
 
 /*--------------------------------------------------------------------*/
@@ -59,6 +60,11 @@ struct procuse {
 	struct proc		*fm;
 };
 
+struct procpriv {
+	VTAILQ_ENTRY(procpriv)	list;
+	const char		*vmod;
+};
+
 /*--------------------------------------------------------------------*/
 
 static void
@@ -355,3 +361,28 @@ VCC_XrefTable(struct vcc *tl)
 	VCC_WalkSymbols(tl, vcc_xreftable, SYM_NONE);
 	Fc(tl, 0, "*/\n\n");
 }
+
+/*---------------------------------------------------------------------
+ * mark vmod as referenced, return NULL if not yet marked, vmod if marked
+ */
+
+const char *
+vcc_MarkPriv(struct vcc *tl, struct procprivhead *head,
+    const char *vmod)
+{
+	struct procpriv *pp;
+
+	AN(vmod);
+
+	VTAILQ_FOREACH(pp, head, list) {
+		if (pp->vmod == vmod)
+			return (vmod);
+		AN(strcmp(pp->vmod, vmod));
+	}
+
+	pp = TlAlloc(tl, sizeof *pp);
+	assert(pp != NULL);
+	pp->vmod = vmod;
+	VTAILQ_INSERT_TAIL(head, pp, list);
+	return (NULL);
+}


More information about the varnish-commit mailing list