[master] 9ceeed8aa Fail VCL loading if VMOD objects are left uninitialized.

Poul-Henning Kamp phk at FreeBSD.org
Tue Feb 5 11:00:16 UTC 2019


commit 9ceeed8aa880bdb3eb0378aee1ace3d2dc6fca0f
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Feb 5 10:58:36 2019 +0000

    Fail VCL loading if VMOD objects are left uninitialized.
    
    Allow VMOD writers to permit with NULL_OK flag.
    
    Only call object destructor on initialized objects.
    
    Fixes #2839

diff --git a/bin/varnishtest/tests/r02839.vtc b/bin/varnishtest/tests/r02839.vtc
new file mode 100644
index 000000000..16525a833
--- /dev/null
+++ b/bin/varnishtest/tests/r02839.vtc
@@ -0,0 +1,32 @@
+varnishtest "Test uninitialized vmod objects"
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl+backend "" -start
+
+varnish v1 -errvcl "Object vo_null not initialized" {
+	import debug;
+
+	backend default { .host = "127.0.0.1"; }
+
+	sub vcl_init {
+		if (false) {
+			new null = debug.obj();
+		}
+	}
+}
+
+varnish v1 -vcl {
+	import debug;
+
+	backend default { .host = "127.0.0.1"; }
+
+	sub vcl_init {
+		if (false) {
+			new null = debug.obj_opt();
+		}
+	}
+}
diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c
index d9bc4f84b..09c1d4704 100644
--- a/lib/libvcc/vcc_compile.c
+++ b/lib/libvcc/vcc_compile.c
@@ -293,6 +293,7 @@ EmitInitFini(const struct vcc *tl)
 {
 	struct inifin *p, *q = NULL;
 	unsigned has_event = 0;
+	struct symbol *sy;
 
 	Fh(tl, 0, "\n");
 	Fh(tl, 0, "static unsigned vgc_inistep;\n");
@@ -317,6 +318,13 @@ EmitInitFini(const struct vcc *tl)
 		if (VSB_len(p->event))
 			has_event = 1;
 	}
+	VTAILQ_FOREACH(sy, &tl->sym_objects, sideways) {
+		Fc(tl, 0, "\tif (!%s) {\n", sy->rname);
+		Fc(tl, 0, "\t\tVRT_fail(ctx, "
+		    "\"Object %s not initialized\");\n" , sy->rname);
+		Fc(tl, 0, "\t\treturn(1);\n");
+		Fc(tl, 0, "\t}\n");
+	}
 
 	Fc(tl, 0, "\treturn(0);\n");
 	Fc(tl, 0, "}\n");
@@ -744,6 +752,7 @@ VCC_New(void)
 	VTAILQ_INIT(&tl->tokens);
 	VTAILQ_INIT(&tl->sources);
 	VTAILQ_INIT(&tl->procs);
+	VTAILQ_INIT(&tl->sym_objects);
 
 	tl->nsources = 0;
 
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 4e7e94c05..ece13c662 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -134,6 +134,7 @@ struct symbol {
 	unsigned			magic;
 #define SYMBOL_MAGIC			0x3368c9fb
 	VTAILQ_ENTRY(symbol)		list;
+	VTAILQ_ENTRY(symbol)		sideways;
 	VTAILQ_HEAD(,symbol)		children;
 
 	char				*name;
@@ -255,6 +256,8 @@ struct vcc {
 	const char		*default_director;
 	const char		*default_probe;
 
+	VTAILQ_HEAD(, symbol)	sym_objects;
+
 	unsigned		unique;
 	unsigned		vmod_count;
 };
diff --git a/lib/libvcc/vcc_vmod.c b/lib/libvcc/vcc_vmod.c
index 678821429..483411010 100644
--- a/lib/libvcc/vcc_vmod.c
+++ b/lib/libvcc/vcc_vmod.c
@@ -353,6 +353,7 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
 	struct vsb *buf;
 	const struct vjsn_val *vv, *vf;
 	const char *p;
+	int null_ok = 0;
 
 	(void)sym;
 	ExpectErr(tl, ID);
@@ -380,8 +381,19 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
 	}
 
 	CAST_OBJ_NOTNULL(vv, sy2->eval_priv, VJSN_VAL_MAGIC);
+	// vv = object name
 
 	vv = VTAILQ_NEXT(vv, list);
+	// vv = flags
+	assert(vv->type == VJSN_OBJECT);
+	VTAILQ_FOREACH(vf, &vv->children, list)
+		if (!strcmp(vf->name, "NULL_OK") && vf->type == VJSN_TRUE)
+			null_ok = 1;
+	if (!null_ok)
+		VTAILQ_INSERT_TAIL(&tl->sym_objects, sy1, sideways);
+
+	vv = VTAILQ_NEXT(vv, list);
+	// vv = struct name
 
 	Fh(tl, 0, "static %s *%s;\n\n", vv->value, sy1->rname);
 	vv = VTAILQ_NEXT(vv, list);
@@ -412,7 +424,8 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
 	vf = VTAILQ_FIRST(&vf->children);
 	vf = VTAILQ_NEXT(vf, list);
 	ifp = New_IniFin(tl);
-	VSB_printf(ifp->fin, "\t\t%s(&%s);", vf->value, sy1->rname);
+	VSB_printf(ifp->fin, "\t\tif (%s)\n", sy1->rname);
+	VSB_printf(ifp->fin, "\t\t\t\t%s(&%s);", vf->value, sy1->rname);
 
 	/* Instantiate symbols for the methods */
 	buf = VSB_new_auto();
diff --git a/lib/libvcc/vmodtool.py b/lib/libvcc/vmodtool.py
index f7886920c..3ad485273 100755
--- a/lib/libvcc/vmodtool.py
+++ b/lib/libvcc/vmodtool.py
@@ -502,6 +502,7 @@ class Stanza(object):
         self.doc = doc
         self.vcc = vcc
         self.rstlbl = None
+        self.null_ok = False
         self.methods = None
         self.proto = None
         self.parse()
@@ -708,6 +709,9 @@ class ObjectStanza(Stanza):
     ''' $Object TYPE class ( ARGUMENTS ) '''
 
     def parse(self):
+        if self.toks[1] == "NULL_OK":
+            self.toks.pop(1)
+            self.null_ok = True
         self.proto = ProtoType(self, retval=False)
         self.proto.obj = "x" + self.proto.name
 
@@ -768,6 +772,7 @@ class ObjectStanza(Stanza):
         ll = [
             "$OBJ",
             self.proto.name,
+	    { "NULL_OK": self.null_ok },
             "struct %s%s_%s" %
             (self.vcc.sympfx, self.vcc.modname, self.proto.name),
         ]
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 65464fd32..016bca407 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -218,7 +218,7 @@ in nanoseconds.
 
 For comparable results, a higher size run should called first and discarded.
 
-$Object obj_opt(PRIV_CALL, PRIV_VCL, PRIV_TASK,
+$Object NULL_OK obj_opt(PRIV_CALL, PRIV_VCL, PRIV_TASK,
 		[STRING s], [BOOL b])
 
 Test object constructor with all the fancy stuff.
diff --git a/lib/libvmod_debug/vmod_debug_obj.c b/lib/libvmod_debug/vmod_debug_obj.c
index 0dea592a3..34eacca75 100644
--- a/lib/libvmod_debug/vmod_debug_obj.c
+++ b/lib/libvmod_debug/vmod_debug_obj.c
@@ -68,7 +68,6 @@ xyzzy_obj__fini(struct xyzzy_debug_obj **op)
 	AN(op);
 	AN(*op);
 	FREE_OBJ(*op);
-	*op = NULL;
 }
 
 VCL_VOID v_matchproto_()
@@ -204,8 +203,7 @@ xyzzy_obj_opt__fini(struct xyzzy_debug_obj_opt **op)
 	struct xyzzy_debug_obj_opt *o;
 
 	AN(op);
-	if (*op == NULL)
-		return;	/* init has failed */
+	AN(*op);
 
 	TAKE_OBJ_NOTNULL(o, op, VMOD_DEBUG_OBJ_OPT_MAGIC);
 


More information about the varnish-commit mailing list