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 {
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;
};
......@@ -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)
......
......@@ -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;
......
......@@ -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)
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
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