[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