[master] bba4b145d vcc: Expand SUB type, add possible calling methods

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


commit bba4b145df403f12731a8670cbdd1d38555fad19
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Tue Dec 17 14:06:26 2019 +0100

    vcc: Expand SUB type, add possible calling methods
    
    Until now, the VCC SUB type represented the literal name of a
    vcc-generated C function, which was used to expand the VCL "call"
    action.
    
    We now add a struct to describe VCL subs and calculate a bitmask which
    represents the bilt-in subs which a SUB may be called from (the
    "okmask"),
    
    This is in preparation of the goal to add a VCL_SUB vmod type which
    will allow VMODs to call into vcl subs.
    
    We add to the vcl shared object a struct vcl_sub for each sub, which
    contains:
    
            - a methods bitmask defining which built-in subs this sub may
              be called from (directly or indirectly)
            - the name as seen from vcl
            - a pointer back to the VCL_conf
            - the function pointer to the vcl_func_f
            - a unique number
    
    About the methods bitmask:
    
    It contains the VCL_MET_* bits of of built-in subs (traditionally
    called methods) which are allowed to call this sub.
    
    It is intended for checks like
    
            if (sub->methods & ctx->method) {
                    sub->func(ctx);
                    return;
            } else {
                    VRT_fail(ctx, "not allowed here");
                    return;
            }
    
    In existing compile-time calls, we already check if used objects and
    returned actions are allowed within the respective calling context.
    
    To build the methods bitmask, we begin with a VCL_MET_TASK_ALL
    bitfield and clear the bits of methods which would not be allowed for
    any used object or returned action.
    
    About the VCL_conf pointer:
    
    Each VCL SUB belongs to a VCL, this pointer will allow to check that
    it is only ever used from the right VCL.
    
    About the unique number:
    
    By numbering vcl subs (per VCL), we can later implement a recursion
    check using a bitmask.
    
    In struct VCL_conf, we record the total number of subs.

diff --git a/include/vcc_interface.h b/include/vcc_interface.h
index 353cb0d45..32f09b970 100644
--- a/include/vcc_interface.h
+++ b/include/vcc_interface.h
@@ -81,3 +81,15 @@ struct vpi_ii {
 
 void VPI_re_init(struct vre **, const char *);
 void VPI_re_fini(struct vre *);
+
+/* VCL_SUB type */
+
+struct vcl_sub {
+	unsigned		magic;
+#define VCL_SUB_MAGIC		0x12c1750b
+	const unsigned		methods;	// ok &= ctx->method
+	const char * const	name;
+	const struct VCL_conf	*vcl_conf;
+	vcl_func_f		*func;
+	unsigned		n;
+};
diff --git a/include/vrt.h b/include/vrt.h
index b882b1136..1b0765454 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -211,6 +211,7 @@ struct vsc_seg;
 struct vsl_log;
 struct vsmw_cluster;
 struct ws;
+struct vcl_sub;
 
 /***********************************************************************
  * VCL_STRANDS:
@@ -283,6 +284,7 @@ typedef const struct vre *			VCL_REGEX;
 typedef const struct stevedore *		VCL_STEVEDORE;
 typedef const struct strands *			VCL_STRANDS;
 typedef const char *				VCL_STRING;
+typedef const struct vcl_sub *			VCL_SUB;
 typedef vtim_real				VCL_TIME;
 typedef struct vcl *				VCL_VCL;
 typedef void					VCL_VOID;
@@ -335,6 +337,8 @@ struct vrt_ctx {
 #define VRT_CTX		const struct vrt_ctx *ctx
 void VRT_CTX_Assert(VRT_CTX);
 
+typedef void vcl_func_f(VRT_CTX);
+
 /***********************************************************************
  * This is the interface structure to a compiled VMOD
  * (produced by vmodtool.py)
diff --git a/lib/libvcc/generate.py b/lib/libvcc/generate.py
index 238969bcc..1b23b6282 100755
--- a/lib/libvcc/generate.py
+++ b/lib/libvcc/generate.py
@@ -666,7 +666,6 @@ fo.write("""
 typedef int vcl_event_f(VRT_CTX, enum vcl_event_e);
 typedef int vcl_init_f(VRT_CTX);
 typedef void vcl_fini_f(VRT_CTX);
-typedef void vcl_func_f(VRT_CTX);
 
 struct VCL_conf {
 	unsigned		magic;
@@ -679,6 +678,7 @@ struct VCL_conf {
 	const struct vpi_ref	*ref;
 
 	int			nsrc;
+	unsigned		nsub;
 	const char		**srcname;
 	const char		**srcbody;
 
diff --git a/lib/libvcc/vcc_action.c b/lib/libvcc/vcc_action.c
index 10ee8e4c5..ec263fd8e 100644
--- a/lib/libvcc/vcc_action.c
+++ b/lib/libvcc/vcc_action.c
@@ -315,7 +315,7 @@ vcc_act_return_vcl(struct vcc *tl)
 static void v_matchproto_(sym_act_f)
 vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
 {
-	unsigned hand;
+	unsigned hand, mask;
 	const char *h;
 
 	(void)t;
@@ -335,6 +335,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
 		if (vcc_IdIs(tl->t, #l)) {		\
 			hand = VCL_RET_ ## U;		\
 			h = #U;				\
+			mask = B;			\
 		}
 #include "tbl/vcl_returns.h"
 	if (h == NULL) {
@@ -344,7 +345,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
 	}
 	assert(hand < VCL_RET_MAX);
 
-	vcc_ProcAction(tl->curproc, hand, tl->t);
+	vcc_ProcAction(tl->curproc, hand, mask, tl->t);
 	vcc_NextToken(tl);
 	if (tl->t->tok == '(') {
 		if (hand == VCL_RET_SYNTH || hand == VCL_RET_ERROR)
diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c
index 4d728d7d7..d4dfa0601 100644
--- a/lib/libvcc/vcc_compile.c
+++ b/lib/libvcc/vcc_compile.c
@@ -59,6 +59,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
 
 #include "vcc_compile.h"
 
@@ -160,6 +161,7 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym)
 	AN(p->body);
 	p->cname = VSB_new_auto();
 	AN(p->cname);
+	p->okmask = VCL_MET_TASK_ALL;
 	sym->proc = p;
 	p->sym = sym;
 	return (p);
@@ -170,11 +172,21 @@ vcc_EmitProc(struct vcc *tl, struct proc *p)
 {
 	struct vsb *vsbm;
 
+	AN(p->okmask);
 	AZ(VSB_finish(p->cname));
 	AZ(VSB_finish(p->prologue));
 	AZ(VSB_finish(p->body));
 
 	Fh(tl, 1, "vcl_func_f %s;\n", VSB_data(p->cname));
+	Fh(tl, 1, "const struct vcl_sub sub_%s[1] = {{\n",
+	   VSB_data(p->cname));
+	Fh(tl, 1, "\t.magic\t\t= VCL_SUB_MAGIC,\n");
+	Fh(tl, 1, "\t.methods\t= 0x%x,\n", p->okmask);
+	Fh(tl, 1, "\t.name\t\t= \"%.*s\",\n", PF(p->name));
+	Fh(tl, 1, "\t.vcl_conf\t= &VCL_conf,\n");
+	Fh(tl, 1, "\t.func\t\t= %s,\n", VSB_data(p->cname));
+	Fh(tl, 1, "\t.n\t\t= %d\n", tl->nsub++);
+	Fh(tl, 1, "}};\n");
 	/*
 	 * TODO: v_dont_optimize for custom subs called from vcl_init/fini only
 	 *
@@ -526,6 +538,7 @@ EmitStruct(const struct vcc *tl)
 	Fc(tl, 0, "\t.ref = VGC_ref,\n");
 	Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
 	Fc(tl, 0, "\t.nsrc = VGC_NSRCS,\n");
+	Fc(tl, 0, "\t.nsub = %d,\n", tl->nsub);
 	Fc(tl, 0, "\t.srcname = srcname,\n");
 	Fc(tl, 0, "\t.srcbody = srcbody,\n");
 	Fc(tl, 0, "\t.nvmod = %u,\n", tl->vmod_count);
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 47d0fdd62..814414c66 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -211,6 +211,7 @@ struct proc {
 	unsigned		ret_bitmap;
 	unsigned		called;
 	unsigned		active;
+	unsigned		okmask;
 	struct token		*return_tok[VCL_RET_MAX];
 	struct vsb		*cname;
 	struct vsb		*prologue;
@@ -265,6 +266,7 @@ struct vcc {
 						 */
 	struct vsb		*sb;
 	int			err;
+	unsigned		nsub;
 	struct proc		*curproc;
 	VTAILQ_HEAD(, proc)	procs;
 
@@ -427,7 +429,7 @@ void VCC_InstanceInfo(struct vcc *tl);
 void VCC_XrefTable(struct vcc *);
 
 void vcc_AddCall(struct vcc *, struct token *, struct symbol *);
-void vcc_ProcAction(struct proc *p, unsigned action, struct token *t);
+void vcc_ProcAction(struct proc *, unsigned, unsigned, struct token *);
 int vcc_CheckAction(struct vcc *tl);
 
 
diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c
index b6f08bd71..091874895 100644
--- a/lib/libvcc/vcc_xref.c
+++ b/lib/libvcc/vcc_xref.c
@@ -161,11 +161,12 @@ vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym)
 }
 
 void
-vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
+vcc_ProcAction(struct proc *p, unsigned returns, unsigned mask, struct token *t)
 {
 
 	assert(returns < VCL_RET_MAX);
 	p->ret_bitmap |= (1U << returns);
+	p->okmask &= mask;
 	/* Record the first instance of this return */
 	if (p->return_tok[returns] == NULL)
 		p->return_tok[returns] = t;
@@ -212,6 +213,7 @@ vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
 			vcc_ErrWhere(tl, pc->t);
 			return (1);
 		}
+		p->okmask &= pc->sym->proc->okmask;
 	}
 	p->active = 0;
 	p->called++;
@@ -279,22 +281,27 @@ vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
 }
 
 static struct procuse *
-vcc_FindIllegalUse(struct vcc *tl, const struct proc *p, const struct method *m)
+vcc_FindIllegalUse(struct vcc *tl, struct proc *p, const struct method *m)
 {
-	struct procuse *pu, *pw;
+	struct procuse *pu, *pw, *r = NULL;
 
 	VTAILQ_FOREACH(pu, &p->uses, list) {
+		p->okmask &= pu->mask;
+		if (m == NULL)
+			continue;
 		pw = vcc_illegal_write(tl, pu, m);
+		if (r != NULL)
+			continue;
 		if (tl->err)
-			return (pw);
-		if (!(pu->mask & m->bitval))
-			return (pu);
+			r = pw;
+		else if (!(pu->mask & m->bitval))
+			r = pu;
 	}
-	return (NULL);
+	return (r);
 }
 
 static int
-vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
+vcc_CheckUseRecurse(struct vcc *tl, struct proc *p,
     const struct method *m)
 {
 	struct proccall *pc;
@@ -319,6 +326,7 @@ vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
 			vcc_ErrWhere(tl, pc->t);
 			return (1);
 		}
+		p->okmask &= pc->sym->proc->okmask;
 	}
 	return (0);
 }
@@ -331,8 +339,6 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym)
 
 	p = sym->proc;
 	AN(p);
-	if (p->method == NULL)
-		return;
 	pu = vcc_FindIllegalUse(tl, p, p->method);
 	if (pu != NULL) {
 		vcc_ErrWhere2(tl, pu->t1, pu->t2);


More information about the varnish-commit mailing list