[master] ae87e52f9 vcc: check for impossible subs at compile time

Nils Goroll nils.goroll at uplex.de
Mon Feb 8 17:52:03 UTC 2021

commit ae87e52f926b8248622e72851573129ccc3ef605
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Sat Feb 6 14:25:37 2021 +0100

    vcc: check for impossible subs at compile time
    We call those subs impossible which use a combination of variables not
    being available together from any of the built-in subroutines (aka
    methods), for example::
            sub foo {
                    set req.http.impossible = beresp.reason;
    For this example, there is no built-in subroutine for which both req
    and beresp were available, so it can not possibly be valid in any
    As long as subs were actually called directly or indirectly from a
    built-in sub, VCC did already detect the problem. For the above
    example, if `sub vcl_recv { call foo; }` existed, VCC would complain
    about beresp.reason not being accessible from vcl_recv.
    Except, when vcc_err_unref was disabled, the example would pass
    without error, and likewise it will with calls which we are about to
    We now add a check to detect impossible subroutines. It happens in a
    second walk over the VCL's SUB symbols in order to keep the more
    precise error messages for calls rooting in one of the built-in subs.
    This change also changes the order of error reporting slightly and
    incorporates, indirectly, the vcc_CheckUses() check moved in
    v00020.vtc now has the "Impossible Subroutine with vcc_err_unref off"
    check, while the newly added m00053.vtc has been changed to test
    failure of the impossible sub at compile time rather than at runtime.
    This change was triggered by feedback from Dridi

diff --git a/bin/varnishtest/tests/v00020.vtc b/bin/varnishtest/tests/v00020.vtc
index 068135836..c9d41647b 100644
--- a/bin/varnishtest/tests/v00020.vtc
+++ b/bin/varnishtest/tests/v00020.vtc
@@ -246,6 +246,17 @@ varnish v1 -errvcl {Not available in subroutine 'vcl_recv'.} {
+varnish v1 -cliok "param.set vcc_err_unref off"
+varnish v1 -errvcl {Impossible Subroutine} {
+	backend b { .host = ""; }
+	sub foo {
+		set req.http.foo = 100 + beresp.status;
+	}
+varnish v1 -cliok "param.set vcc_err_unref on"
 varnish v1 -errvcl {
 ('<vcl.inline>' Line 4 Pos 44) -- (Pos 49)
         sub foo { set req.http.foo = 100 + beresp.status; }
diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c
index 091874895..c2e63ed76 100644
--- a/lib/libvcc/vcc_xref.c
+++ b/lib/libvcc/vcc_xref.c
@@ -140,10 +140,6 @@ vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
 		WRONG("wrong xref use");
 	VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
-	if (pu->mask == 0)
-		if (vcc_CheckUses(tl))
-			AN(tl->err);
@@ -355,11 +351,34 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym)
+ * Used from a second symbol walk because vcc_checkuses is more precise for
+ * subroutines called from methods. We catch here subs used for dynamic calls
+ * and with vcc_err_unref = off
+ */
+static void
+vcc_checkpossible(struct vcc *tl, const struct symbol *sym)
+	struct proc *p;
+	p = sym->proc;
+	AN(p);
+	if (p->okmask != 0)
+		return;
+	VSB_cat(tl->sb, "Impossible Subroutine");
+	vcc_ErrWhere(tl, p->name);
 vcc_CheckUses(struct vcc *tl)
 	VCC_WalkSymbols(tl, vcc_checkuses, SYM_MAIN, SYM_SUB);
+	if (tl->err)
+		return (tl->err);
+	VCC_WalkSymbols(tl, vcc_checkpossible, SYM_MAIN, SYM_SUB);
 	return (tl->err);

More information about the varnish-commit mailing list