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.
parent ee50b462
...@@ -81,3 +81,15 @@ struct vpi_ii { ...@@ -81,3 +81,15 @@ struct vpi_ii {
void VPI_re_init(struct vre **, const char *); void VPI_re_init(struct vre **, const char *);
void VPI_re_fini(struct vre *); 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;
};
...@@ -211,6 +211,7 @@ struct vsc_seg; ...@@ -211,6 +211,7 @@ struct vsc_seg;
struct vsl_log; struct vsl_log;
struct vsmw_cluster; struct vsmw_cluster;
struct ws; struct ws;
struct vcl_sub;
/*********************************************************************** /***********************************************************************
* VCL_STRANDS: * VCL_STRANDS:
...@@ -283,6 +284,7 @@ typedef const struct vre * VCL_REGEX; ...@@ -283,6 +284,7 @@ typedef const struct vre * VCL_REGEX;
typedef const struct stevedore * VCL_STEVEDORE; typedef const struct stevedore * VCL_STEVEDORE;
typedef const struct strands * VCL_STRANDS; typedef const struct strands * VCL_STRANDS;
typedef const char * VCL_STRING; typedef const char * VCL_STRING;
typedef const struct vcl_sub * VCL_SUB;
typedef vtim_real VCL_TIME; typedef vtim_real VCL_TIME;
typedef struct vcl * VCL_VCL; typedef struct vcl * VCL_VCL;
typedef void VCL_VOID; typedef void VCL_VOID;
...@@ -335,6 +337,8 @@ struct vrt_ctx { ...@@ -335,6 +337,8 @@ struct vrt_ctx {
#define VRT_CTX const struct vrt_ctx *ctx #define VRT_CTX const struct vrt_ctx *ctx
void VRT_CTX_Assert(VRT_CTX); void VRT_CTX_Assert(VRT_CTX);
typedef void vcl_func_f(VRT_CTX);
/*********************************************************************** /***********************************************************************
* This is the interface structure to a compiled VMOD * This is the interface structure to a compiled VMOD
* (produced by vmodtool.py) * (produced by vmodtool.py)
......
...@@ -666,7 +666,6 @@ fo.write(""" ...@@ -666,7 +666,6 @@ fo.write("""
typedef int vcl_event_f(VRT_CTX, enum vcl_event_e); typedef int vcl_event_f(VRT_CTX, enum vcl_event_e);
typedef int vcl_init_f(VRT_CTX); typedef int vcl_init_f(VRT_CTX);
typedef void vcl_fini_f(VRT_CTX); typedef void vcl_fini_f(VRT_CTX);
typedef void vcl_func_f(VRT_CTX);
struct VCL_conf { struct VCL_conf {
unsigned magic; unsigned magic;
...@@ -679,6 +678,7 @@ struct VCL_conf { ...@@ -679,6 +678,7 @@ struct VCL_conf {
const struct vpi_ref *ref; const struct vpi_ref *ref;
int nsrc; int nsrc;
unsigned nsub;
const char **srcname; const char **srcname;
const char **srcbody; const char **srcbody;
......
...@@ -315,7 +315,7 @@ vcc_act_return_vcl(struct vcc *tl) ...@@ -315,7 +315,7 @@ vcc_act_return_vcl(struct vcc *tl)
static void v_matchproto_(sym_act_f) static void v_matchproto_(sym_act_f)
vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym) vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
{ {
unsigned hand; unsigned hand, mask;
const char *h; const char *h;
(void)t; (void)t;
...@@ -335,6 +335,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym) ...@@ -335,6 +335,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
if (vcc_IdIs(tl->t, #l)) { \ if (vcc_IdIs(tl->t, #l)) { \
hand = VCL_RET_ ## U; \ hand = VCL_RET_ ## U; \
h = #U; \ h = #U; \
mask = B; \
} }
#include "tbl/vcl_returns.h" #include "tbl/vcl_returns.h"
if (h == NULL) { if (h == NULL) {
...@@ -344,7 +345,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym) ...@@ -344,7 +345,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
} }
assert(hand < VCL_RET_MAX); assert(hand < VCL_RET_MAX);
vcc_ProcAction(tl->curproc, hand, tl->t); vcc_ProcAction(tl->curproc, hand, mask, tl->t);
vcc_NextToken(tl); vcc_NextToken(tl);
if (tl->t->tok == '(') { if (tl->t->tok == '(') {
if (hand == VCL_RET_SYNTH || hand == VCL_RET_ERROR) if (hand == VCL_RET_SYNTH || hand == VCL_RET_ERROR)
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include "vcc_compile.h" #include "vcc_compile.h"
...@@ -160,6 +161,7 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym) ...@@ -160,6 +161,7 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym)
AN(p->body); AN(p->body);
p->cname = VSB_new_auto(); p->cname = VSB_new_auto();
AN(p->cname); AN(p->cname);
p->okmask = VCL_MET_TASK_ALL;
sym->proc = p; sym->proc = p;
p->sym = sym; p->sym = sym;
return (p); return (p);
...@@ -170,11 +172,21 @@ vcc_EmitProc(struct vcc *tl, struct proc *p) ...@@ -170,11 +172,21 @@ vcc_EmitProc(struct vcc *tl, struct proc *p)
{ {
struct vsb *vsbm; struct vsb *vsbm;
AN(p->okmask);
AZ(VSB_finish(p->cname)); AZ(VSB_finish(p->cname));
AZ(VSB_finish(p->prologue)); AZ(VSB_finish(p->prologue));
AZ(VSB_finish(p->body)); AZ(VSB_finish(p->body));
Fh(tl, 1, "vcl_func_f %s;\n", VSB_data(p->cname)); 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 * TODO: v_dont_optimize for custom subs called from vcl_init/fini only
* *
...@@ -526,6 +538,7 @@ EmitStruct(const struct vcc *tl) ...@@ -526,6 +538,7 @@ EmitStruct(const struct vcc *tl)
Fc(tl, 0, "\t.ref = VGC_ref,\n"); Fc(tl, 0, "\t.ref = VGC_ref,\n");
Fc(tl, 0, "\t.nref = VGC_NREFS,\n"); Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
Fc(tl, 0, "\t.nsrc = VGC_NSRCS,\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.srcname = srcname,\n");
Fc(tl, 0, "\t.srcbody = srcbody,\n"); Fc(tl, 0, "\t.srcbody = srcbody,\n");
Fc(tl, 0, "\t.nvmod = %u,\n", tl->vmod_count); Fc(tl, 0, "\t.nvmod = %u,\n", tl->vmod_count);
......
...@@ -211,6 +211,7 @@ struct proc { ...@@ -211,6 +211,7 @@ struct proc {
unsigned ret_bitmap; unsigned ret_bitmap;
unsigned called; unsigned called;
unsigned active; unsigned active;
unsigned okmask;
struct token *return_tok[VCL_RET_MAX]; struct token *return_tok[VCL_RET_MAX];
struct vsb *cname; struct vsb *cname;
struct vsb *prologue; struct vsb *prologue;
...@@ -265,6 +266,7 @@ struct vcc { ...@@ -265,6 +266,7 @@ struct vcc {
*/ */
struct vsb *sb; struct vsb *sb;
int err; int err;
unsigned nsub;
struct proc *curproc; struct proc *curproc;
VTAILQ_HEAD(, proc) procs; VTAILQ_HEAD(, proc) procs;
...@@ -427,7 +429,7 @@ void VCC_InstanceInfo(struct vcc *tl); ...@@ -427,7 +429,7 @@ void VCC_InstanceInfo(struct vcc *tl);
void VCC_XrefTable(struct vcc *); void VCC_XrefTable(struct vcc *);
void vcc_AddCall(struct vcc *, struct token *, struct symbol *); 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); int vcc_CheckAction(struct vcc *tl);
......
...@@ -161,11 +161,12 @@ vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym) ...@@ -161,11 +161,12 @@ vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym)
} }
void 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); assert(returns < VCL_RET_MAX);
p->ret_bitmap |= (1U << returns); p->ret_bitmap |= (1U << returns);
p->okmask &= mask;
/* Record the first instance of this return */ /* Record the first instance of this return */
if (p->return_tok[returns] == NULL) if (p->return_tok[returns] == NULL)
p->return_tok[returns] = t; p->return_tok[returns] = t;
...@@ -212,6 +213,7 @@ vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap) ...@@ -212,6 +213,7 @@ vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
vcc_ErrWhere(tl, pc->t); vcc_ErrWhere(tl, pc->t);
return (1); return (1);
} }
p->okmask &= pc->sym->proc->okmask;
} }
p->active = 0; p->active = 0;
p->called++; p->called++;
...@@ -279,22 +281,27 @@ vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m) ...@@ -279,22 +281,27 @@ vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
} }
static struct procuse * 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) { VTAILQ_FOREACH(pu, &p->uses, list) {
p->okmask &= pu->mask;
if (m == NULL)
continue;
pw = vcc_illegal_write(tl, pu, m); pw = vcc_illegal_write(tl, pu, m);
if (r != NULL)
continue;
if (tl->err) if (tl->err)
return (pw); r = pw;
if (!(pu->mask & m->bitval)) else if (!(pu->mask & m->bitval))
return (pu); r = pu;
} }
return (NULL); return (r);
} }
static int static int
vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p, vcc_CheckUseRecurse(struct vcc *tl, struct proc *p,
const struct method *m) const struct method *m)
{ {
struct proccall *pc; struct proccall *pc;
...@@ -319,6 +326,7 @@ vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p, ...@@ -319,6 +326,7 @@ vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
vcc_ErrWhere(tl, pc->t); vcc_ErrWhere(tl, pc->t);
return (1); return (1);
} }
p->okmask &= pc->sym->proc->okmask;
} }
return (0); return (0);
} }
...@@ -331,8 +339,6 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym) ...@@ -331,8 +339,6 @@ vcc_checkuses(struct vcc *tl, const struct symbol *sym)
p = sym->proc; p = sym->proc;
AN(p); AN(p);
if (p->method == NULL)
return;
pu = vcc_FindIllegalUse(tl, p, p->method); pu = vcc_FindIllegalUse(tl, p, p->method);
if (pu != NULL) { if (pu != NULL) {
vcc_ErrWhere2(tl, pu->t1, pu->t2); vcc_ErrWhere2(tl, pu->t1, pu->t2);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment