[master] 8ae3d9782 Extend the syntax to 'import vmod [as name] [from "path"]; '

Poul-Henning Kamp phk at FreeBSD.org
Mon May 20 10:22:10 UTC 2019


commit 8ae3d978224587ae6021a78d5821b9978ae65f24
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon May 20 10:20:43 2019 +0000

    Extend the syntax to 'import vmod [as name] [from "path"];'
    
    There are a surprising number of subtle corner cases here, and I
    think I have handled them all correctly, but caveat emptor...

diff --git a/bin/varnishtest/tests/m00000.vtc b/bin/varnishtest/tests/m00000.vtc
index 1931db422..a62ff527b 100644
--- a/bin/varnishtest/tests/m00000.vtc
+++ b/bin/varnishtest/tests/m00000.vtc
@@ -11,10 +11,12 @@ varnish v1 -vcl+backend {
 	import debug;
 	import vtc;
 	import debug;		// again
+	import debug as dbg;
+	import debug as dbg;	// again
 
 	sub vcl_init {
-		new objx = debug.obj();
-		debug.vsc_new();
+		new objx = dbg.obj();
+		dbg.vsc_new();
 	}
 
 	sub vcl_synth {
diff --git a/bin/varnishtest/tests/m00008.vtc b/bin/varnishtest/tests/m00008.vtc
index a0bc5b2a3..7b5647487 100644
--- a/bin/varnishtest/tests/m00008.vtc
+++ b/bin/varnishtest/tests/m00008.vtc
@@ -12,6 +12,11 @@ varnish v1 -errvcl {Module debug conflicts with other symbol.} {
 	}
 }
 
+varnish v1 -errvcl {Another module already imported as foo} {
+	import debug as foo;
+	import directors as foo;
+}
+
 server s1 {
 	rxreq
 	txresp
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 58eb570c6..20213c0b9 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -144,7 +144,7 @@ struct symbol {
 	int				hirev;
 
 	struct symbol			*parent;
-	const struct symbol		*vmod;
+	const char			*vmod_name;
 
 	sym_wildcard_t			*wildcard;
 	vcc_kind_t			kind;
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index 9638b519f..c74cc4c4b 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -359,10 +359,10 @@ vcc_priv_arg(struct vcc *tl, const char *p, const struct symbol *sym)
 	struct procprivhead *marklist = NULL;
 
 	AN(sym);
-	AN(sym->vmod);
+	AN(sym->vmod_name);
 
 	if (!strcmp(p, "PRIV_VCL"))
-		return (vcc_mk_expr(VOID, "&vmod_priv_%s", sym->vmod->name));
+		return (vcc_mk_expr(VOID, "&vmod_priv_%s", sym->vmod_name));
 
 	if (!strcmp(p, "PRIV_CALL")) {
 		bprintf(buf, "vmod_priv_%u", tl->unique++);
@@ -383,9 +383,9 @@ vcc_priv_arg(struct vcc *tl, const char *p, const struct symbol *sym)
 	}
 	AN(f);
 	AN(marklist);
-	bprintf(buf, "ARG_priv_%s_%s", f, sym->vmod->name);
+	bprintf(buf, "ARG_priv_%s_%s", f, sym->vmod_name);
 
-	if (vcc_MarkPriv(tl, marklist, sym->vmod->name) == NULL)
+	if (vcc_MarkPriv(tl, marklist, sym->vmod_name) == NULL)
 		VSB_printf(tl->curproc->prologue,
 			   "  struct vmod_priv *%s = "
 			   "VRT_priv_%s(ctx, &VGC_vmod_%s);\n"
@@ -394,7 +394,7 @@ vcc_priv_arg(struct vcc *tl, const char *p, const struct symbol *sym)
 			   "for vmod %s\");\n"
 			   "    return;\n"
 			   "  }\n",
-			   buf, f, sym->vmod->name, buf, f, sym->vmod->name);
+			   buf, f, sym->vmod_name, buf, f, sym->vmod_name);
 	return (vcc_mk_expr(VOID, "%s", buf));
 }
 
diff --git a/lib/libvcc/vcc_vmod.c b/lib/libvcc/vcc_vmod.c
index ff4831198..38863ceb5 100644
--- a/lib/libvcc/vcc_vmod.c
+++ b/lib/libvcc/vcc_vmod.c
@@ -64,13 +64,12 @@ vcc_path_dlopen(void *priv, const char *fn)
 }
 
 static void
-func_sym(struct symbol *sym, const struct symbol *vmod,
-    const struct vjsn_val *v)
+func_sym(struct symbol *sym, const char *vmod_name, const struct vjsn_val *v)
 {
 
 	assert(v->type == VJSN_ARRAY);
 	sym->action = vcc_Act_Call;
-	sym->vmod = vmod;
+	sym->vmod_name = vmod_name;
 	sym->eval = vcc_Eval_SymFunc;
 	sym->eval_priv = v;
 	v = VTAILQ_FIRST(&v->children);
@@ -82,17 +81,16 @@ func_sym(struct symbol *sym, const struct symbol *vmod,
 }
 
 static void
-vcc_json_always(struct vcc *tl, const struct symbol *msym)
+vcc_json_always(struct vcc *tl, const struct vjsn *vj, const char *vmod_name)
 {
 	struct inifin *ifp;
-	const struct vjsn *vj;
 	const struct vjsn_val *vv, *vv2;
 	double vmod_syntax = 0.0;
 
+	AN(vj);
+	AN(vmod_name);
 	ifp = NULL;
 
-	CAST_OBJ_NOTNULL(vj, msym->eval_priv, VJSN_MAGIC);
-
 	VTAILQ_FOREACH(vv, &vj->value->children, list) {
 		assert(vv->type == VJSN_ARRAY);
 		vv2 = VTAILQ_FIRST(&vv->children);
@@ -111,13 +109,13 @@ vcc_json_always(struct vcc *tl, const struct symbol *msym)
 			VSB_printf(ifp->ini,
 			    "\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
 			    "\t\treturn(1);",
-			    vv2->value, msym->name);
+			    vv2->value, vmod_name);
 			VSB_printf(ifp->fin,
 			    "\t\t(void)%s(ctx, &vmod_priv_%s,\n"
 			    "\t\t\t    VCL_EVENT_DISCARD);",
-			    vv2->value, msym->name);
+			    vv2->value, vmod_name);
 			VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
-			    vv2->value, msym->name);
+			    vv2->value, vmod_name);
 		} else if (!strcmp(vv2->value, "$FUNC")) {
 		} else if (!strcmp(vv2->value, "$OBJ")) {
 		} else {
@@ -147,66 +145,104 @@ vcc_json_wildcard(struct vcc *tl, struct symbol *msym, struct symbol *tsym)
 		    !strcmp(vv2->value, tsym->name)) {
 			tsym->kind = SYM_FUNC;
 			tsym->noref = 1;
-			func_sym(tsym, msym, VTAILQ_NEXT(vv2, list));
+			func_sym(tsym, msym->vmod_name, VTAILQ_NEXT(vv2, list));
 			return;
 		} else if (!strcmp(vv1->value, "$OBJ") &&
 			   !strcmp(vv2->value, tsym->name)) {
 			tsym->kind = SYM_OBJECT;
 			tsym->eval_priv = vv2;
-			tsym->vmod = msym;
+			tsym->vmod_name = msym->vmod_name;
 			return;
 		}
 	}
 	tl->err = 1;
 }
 
+static const struct vmod_data *
+vcc_VmodSanity(struct vcc *tl, void *hdl, struct token *mod, char *fnp)
+{
+	char buf[256];
+	const struct vmod_data *vmd;
+
+	bprintf(buf, "Vmod_%.*s_Data", PF(mod));
+	vmd = dlsym(hdl, buf);
+	if (vmd == NULL) {
+		VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
+		VSB_printf(tl->sb, "\t(no Vmod_Data symbol)\n");
+		vcc_ErrWhere(tl, mod);
+		return (NULL);
+	}
+	if (vmd->vrt_major == 0 && vmd->vrt_minor == 0 &&
+	    (vmd->abi == NULL || strcmp(vmd->abi, VMOD_ABI_Version) != 0)) {
+		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
+		VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
+			   VMOD_ABI_Version, vmd->abi);
+		vcc_ErrWhere(tl, mod);
+		return (NULL);
+	}
+	if (vmd->vrt_major != 0 && (vmd->vrt_major != VRT_MAJOR_VERSION ||
+	    vmd->vrt_minor > VRT_MINOR_VERSION)) {
+		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
+		VSB_printf(tl->sb, "\tVMOD wants ABI version %u.%u\n",
+		    vmd->vrt_major, vmd->vrt_minor);
+		VSB_printf(tl->sb, "\tvarnishd provides ABI version %u.%u\n",
+		    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
+		vcc_ErrWhere(tl, mod);
+		return (NULL);
+	}
+	if (vmd->name == NULL ||
+	    vmd->func == NULL ||
+	    vmd->func_len <= 0 ||
+	    vmd->proto == NULL ||
+	    vmd->abi == NULL) {
+		VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
+		VSB_printf(tl->sb, "\tInconsistent metadata\n");
+		vcc_ErrWhere(tl, mod);
+		return (NULL);
+	}
+	if (!vcc_IdIs(mod, vmd->name)) {
+		VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
+		VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vmd->name);
+		vcc_ErrWhere(tl, mod);
+		return (NULL);
+	}
+	return (vmd);
+}
+
 void
 vcc_ParseImport(struct vcc *tl)
 {
-	char fn[1024], *fnp, *fnpx;
-	char buf[256];
+	char fn[1024], *fnpx;
 	const char *p;
-	struct token *mod, *t1;
+	struct token *mod, *tmod, *t1;
 	struct inifin *ifp;
-	struct symbol *msym;
+	struct symbol *msym, *vsym;
 	const struct vmod_data *vmd;
 	struct vjsn *vj;
-	int again = 0;
 	struct vmod_open vop[1];
 
 	INIT_OBJ(vop, VMOD_OPEN_MAGIC);
 	t1 = tl->t;
 	SkipToken(tl, ID);		/* "import" */
 
-
-	ExpectErr(tl, ID);
+	ExpectErr(tl, ID);		/* "vmod_name" */
 	mod = tl->t;
 	vcc_NextToken(tl);
-	msym = VCC_SymbolGetTok(tl, SYM_NONE, SYMTAB_NOERR, XREF_NONE, mod);
-
-	if (msym != NULL && msym->kind != SYM_VMOD) {
-		/*
-		 * We need to make sure the entire std.* namespace is empty
-		 */
-		VSB_printf(tl->sb, "Module %.*s conflicts with other symbol.\n",
-		    PF(mod));
-		vcc_ErrWhere2(tl, t1, tl->t);
-		return;
-	}
-	if (msym != NULL) {
-		again = 1;
-	} else {
 
-		msym = VCC_SymbolGetTok(tl, SYM_VMOD,
-		    SYMTAB_CREATE, XREF_NONE, mod);
-		ERRCHK(tl);
-		AN(msym);
-		msym->def_b = t1;
-		msym->def_e = tl->t;
+	if (tl->t->tok == ID && vcc_IdIs(tl->t, "as")) {
+		SkipToken(tl, ID);		/* "as" */
+		ExpectErr(tl, ID);		/* "vcl_name" */
+		tmod = tl->t;
+		vcc_NextToken(tl);
+	} else {
+		tmod = mod;
 	}
 
-	VTAILQ_INSERT_TAIL(&tl->sym_vmods, msym, sideways);
-
 	if (tl->t->tok == ID) {
 		if (!vcc_IdIs(tl->t, "from")) {
 			VSB_printf(tl->sb, "Expected 'from path ...'\n");
@@ -234,9 +270,6 @@ vcc_ParseImport(struct vcc *tl)
 
 	SkipToken(tl, ';');
 
-	if (!again)
-		msym->def_e = tl->t;
-
 	if (VFIL_searchpath(tl->vmod_path, vcc_path_dlopen, vop, fn, &fnpx)) {
 		if (vop->err == NULL) {
 			VSB_printf(tl->sb,
@@ -253,72 +286,58 @@ vcc_ParseImport(struct vcc *tl)
 		return;
 	}
 
-	AN(fnpx);
-	fnp = TlDup(tl, fnpx);
-	free(fnpx);
-
-	bprintf(buf, "Vmod_%.*s_Data", PF(mod));
-	vmd = dlsym(vop->hdl, buf);
-	if (vmd == NULL) {
-		VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\t(no Vmod_Data symbol)\n");
-		vcc_ErrWhere(tl, mod);
-		return;
-	}
-	if (vmd->vrt_major == 0 && vmd->vrt_minor == 0 &&
-	    (vmd->abi == NULL || strcmp(vmd->abi, VMOD_ABI_Version) != 0)) {
-		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
-			   VMOD_ABI_Version, vmd->abi);
-		vcc_ErrWhere(tl, mod);
-		return;
-	}
-	if (vmd->vrt_major != 0 && (vmd->vrt_major != VRT_MAJOR_VERSION ||
-	    vmd->vrt_minor > VRT_MINOR_VERSION)) {
-		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\tVMOD wants ABI version %u.%u\n",
-		    vmd->vrt_major, vmd->vrt_minor);
-		VSB_printf(tl->sb, "\tvarnishd provides ABI version %u.%u\n",
-		    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
-		vcc_ErrWhere(tl, mod);
-		return;
-	}
-	if (vmd->name == NULL ||
-	    vmd->func == NULL ||
-	    vmd->func_len <= 0 ||
-	    vmd->proto == NULL ||
-	    vmd->abi == NULL) {
-		VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\tInconsistent metadata\n");
-		vcc_ErrWhere(tl, mod);
+	vmd = vcc_VmodSanity(tl, vop->hdl, mod, fnpx);
+	if (vmd == NULL || tl->err) {
+		AZ(dlclose(vop->hdl));
+		free(fnpx);
 		return;
 	}
 
-	if (!vcc_IdIs(mod, vmd->name)) {
-		VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vmd->name);
-		vcc_ErrWhere(tl, mod);
-		return;
-	}
+	msym = VCC_SymbolGetTok(tl, SYM_NONE, SYMTAB_NOERR, XREF_NONE, tmod);
 
-	if (again && strcmp(vmd->file_id, msym->extra)) {
+	if (msym != NULL && msym->kind == SYM_VMOD &&
+	    !strcmp(msym->extra, vmd->file_id)) {
+		/* Identical import is OK */
+		AZ(dlclose(vop->hdl));
+		free(fnpx);
+		return;
+	} else if (msym != NULL && msym->kind == SYM_VMOD) {
 		VSB_printf(tl->sb,
-		    "Different version of module %.*s already imported.\n",
-		    PF(mod));
+		    "Another module already imported as %.*s.\n", PF(tmod));
+		vcc_ErrWhere2(tl, t1, tl->t);
+		AZ(dlclose(vop->hdl));
+		free(fnpx);
+		return;
+	} else if (msym != NULL) {
+		VSB_printf(tl->sb,
+		    "Module %.*s conflicts with other symbol.\n", PF(tmod));
 		vcc_ErrWhere2(tl, t1, tl->t);
-		VSB_printf(tl->sb, "Previous import was here:\n");
-		vcc_ErrWhere2(tl, msym->def_b, msym->def_e);
-	}
-	if (again) {
 		AZ(dlclose(vop->hdl));
+		free(fnpx);
 		return;
 	}
 
+	msym = VCC_SymbolGetTok(tl, SYM_VMOD, SYMTAB_CREATE, XREF_NONE, tmod);
+	ERRCHK(tl);
+	AN(msym);
+	msym->def_b = t1;
+	msym->def_e = tl->t;
+
+	VTAILQ_FOREACH(vsym, &tl->sym_vmods, sideways) {
+		assert(vsym->kind == SYM_VMOD);
+		if (!strcmp(vsym->extra, vmd->file_id)) {
+			/* Already loaded under different name */
+			msym->eval_priv = vsym->eval_priv;
+			msym->wildcard = vsym->wildcard;
+			msym->extra = vsym->extra;
+			msym->vmod_name = vsym->vmod_name;
+			AZ(dlclose(vop->hdl));
+			return;
+		}
+	}
+
+	VTAILQ_INSERT_TAIL(&tl->sym_vmods, msym, sideways);
+
 	ifp = New_IniFin(tl);
 
 	VSB_printf(ifp->ini, "\tif (VPI_Vmod_Init(ctx,\n");
@@ -328,7 +347,7 @@ vcc_ParseImport(struct vcc *tl)
 	VSB_printf(ifp->ini, "\t    sizeof(%s),\n", vmd->func_name);
 	VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
 	VSB_printf(ifp->ini, "\t    ");
-	VSB_quote(ifp->ini, fnp, -1, VSB_QUOTE_CSTR);
+	VSB_quote(ifp->ini, fnpx, -1, VSB_QUOTE_CSTR);
 	VSB_printf(ifp->ini, ",\n");
 	AN(vmd);
 	AN(vmd->file_id);
@@ -339,7 +358,7 @@ vcc_ParseImport(struct vcc *tl)
 	VSB_printf(ifp->ini, "\t\treturn(1);");
 
 	VSB_printf(tl->fi, "%s VMOD %s ./vmod_cache/_vmod_%.*s.%s */\n",
-	    VCC_INFO_PREFIX, fnp, PF(mod), vmd->file_id);
+	    VCC_INFO_PREFIX, fnpx, PF(mod), vmd->file_id);
 
 	/* XXX: zero the function pointer structure ?*/
 	VSB_printf(ifp->fin, "\t\tVRT_priv_fini(&vmod_priv_%.*s);", PF(mod));
@@ -352,14 +371,16 @@ vcc_ParseImport(struct vcc *tl)
 	msym->eval_priv = vj;
 	msym->wildcard = vcc_json_wildcard;
 	msym->extra = TlDup(tl, vmd->file_id);
+	msym->vmod_name = TlDup(tl, vmd->name);
 
-	vcc_json_always(tl, msym);
+	vcc_json_always(tl, vj, msym->vmod_name);
 
 	Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
 	Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
 	Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
 	Fh(tl, 0, "\n%s\n", vmd->proto);
 	Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
+	free(fnpx);
 }
 
 void v_matchproto_(sym_act_f)
@@ -462,7 +483,7 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
 		AZ(VSB_finish(buf));
 		sy3 = VCC_MkSym(tl, VSB_data(buf), SYM_FUNC, VCL_LOW, VCL_HIGH);
 		AN(sy3);
-		func_sym(sy3, sy2->vmod, VTAILQ_NEXT(vf, list));
+		func_sym(sy3, sy2->vmod_name, VTAILQ_NEXT(vf, list));
 		sy3->extra = p;
 		vv = VTAILQ_NEXT(vv, list);
 	}
diff --git a/lib/libvcc/vmodtool.py b/lib/libvcc/vmodtool.py
index 1b40b10b8..4d8734d4c 100755
--- a/lib/libvcc/vmodtool.py
+++ b/lib/libvcc/vmodtool.py
@@ -603,7 +603,7 @@ class ModuleStanza(Stanza):
             write_rst_hdr(fo, "SYNOPSIS", "=")
             fo.write("\n")
             fo.write(".. parsed-literal::\n\n")
-            fo.write('  import %s [from "path"]\n' % self.vcc.modname)
+            fo.write('  import %s [as name] [from "path"]\n' % self.vcc.modname)
             fo.write("  \n")
             for c in self.vcc.contents:
                 c.synopsis(fo, man)


More information about the varnish-commit mailing list