Commit f03948f4 authored by Nils Goroll's avatar Nils Goroll

initialize PRIV_TASK and PRIV_TOP vmod arguments once per subroutine

... and fail the VCL unless successful.

Providing the PRIVs to vmods is a core function, so error handling
should happen outside vmods.

Besides being safe, this initialization can be more efficient than
previous code for PRIVs used frequently within the same subroutine.

An alternative approach would be to initialize all privs once per
task / top request, but unless all privs are actually used in a VCL,
this approach could impose significant overhead, both in terms of time
and memory. By initializing privs once per sub, we impose overhead for
privs which are referenced but not actually used in a subroutine, but
not for all of the vcl.

Fixes #2708
parent b78a4672
......@@ -104,6 +104,8 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym)
AN(p);
VTAILQ_INIT(&p->calls);
VTAILQ_INIT(&p->uses);
VTAILQ_INIT(&p->priv_tasks);
VTAILQ_INIT(&p->priv_tops);
VTAILQ_INSERT_TAIL(&tl->procs, p, list);
p->prologue = VSB_new_auto();
AN(p->prologue);
......
......@@ -174,6 +174,7 @@ struct symbol {
};
VTAILQ_HEAD(tokenhead, token);
VTAILQ_HEAD(procprivhead, procpriv);
struct proc {
unsigned magic;
......@@ -181,6 +182,8 @@ struct proc {
const struct method *method;
VTAILQ_HEAD(,proccall) calls;
VTAILQ_HEAD(,procuse) uses;
struct procprivhead priv_tasks;
struct procprivhead priv_tops;
VTAILQ_ENTRY(proc) list;
struct token *name;
unsigned ret_bitmap;
......@@ -389,6 +392,8 @@ int vcc_CheckAction(struct vcc *tl);
void vcc_AddUses(struct vcc *, const struct token *, const struct token *,
unsigned mask, const char *use);
int vcc_CheckUses(struct vcc *tl);
const char *vcc_MarkPriv(struct vcc *, struct procprivhead *,
const char *);
#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
#define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
......
......@@ -399,31 +399,49 @@ vcc_Eval_Var(struct vcc *tl, struct expr **e, struct token *t,
*/
static struct expr *
vcc_priv_arg(struct vcc *tl, const char *p, const char *name, const char *vmod)
vcc_priv_arg(struct vcc *tl, const char *p, const struct symbol *sym)
{
struct expr *e2;
char buf[32];
char buf[64];
struct inifin *ifp;
const char *vmod, *f = NULL;
struct procprivhead *marklist = NULL;
AN(sym);
AN(sym->vmod);
vmod = sym->vmod;
(void)name;
if (!strcmp(p, "PRIV_VCL")) {
e2 = vcc_mk_expr(VOID, "&vmod_priv_%s", vmod);
return (vcc_mk_expr(VOID, "&vmod_priv_%s", vmod));
} else if (!strcmp(p, "PRIV_CALL")) {
bprintf(buf, "vmod_priv_%u", tl->unique++);
ifp = New_IniFin(tl);
Fh(tl, 0, "static struct vmod_priv %s;\n", buf);
VSB_printf(ifp->fin, "\tVRT_priv_fini(&%s);", buf);
e2 = vcc_mk_expr(VOID, "&%s", buf);
return (vcc_mk_expr(VOID, "&%s", buf));
} else if (!strcmp(p, "PRIV_TASK")) {
e2 = vcc_mk_expr(VOID,
"VRT_priv_task(ctx, &VGC_vmod_%s)", vmod);
f = "task";
marklist = &tl->curproc->priv_tasks;
} else if (!strcmp(p, "PRIV_TOP")) {
e2 = vcc_mk_expr(VOID,
"VRT_priv_top(ctx, &VGC_vmod_%s)", vmod);
f = "top";
marklist = &tl->curproc->priv_tops;
} else {
WRONG("Wrong PRIV_ type");
}
return (e2);
AN(f);
AN(marklist);
bprintf(buf, "ARG_priv_%s_%s", f, vmod);
if (vcc_MarkPriv(tl, marklist, vmod) == NULL)
VSB_printf(tl->curproc->prologue,
" struct vmod_priv *%s = "
"VRT_priv_%s(ctx, &VGC_vmod_%s);\n"
" if (%s == NULL) {\n"
" VRT_fail(ctx, \"failed to get %s priv "
"for vmod %s\");\n"
" return;\n"
" }\n",
buf, f, vmod, buf, f, vmod);
return (vcc_mk_expr(VOID, "%s", buf));
}
struct func_arg {
......@@ -522,8 +540,7 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
vvp = VTAILQ_FIRST(&vv->children);
if (!memcmp(vvp->value, "PRIV_", 5)) {
fa->result = vcc_priv_arg(tl, vvp->value,
sym->name, sym->vmod);
fa->result = vcc_priv_arg(tl, vvp->value, sym);
continue;
}
fa->type = VCC_Type(vvp->value);
......
......@@ -39,6 +39,7 @@
#include "config.h"
#include <string.h>
#include "vcc_compile.h"
/*--------------------------------------------------------------------*/
......@@ -59,6 +60,11 @@ struct procuse {
struct proc *fm;
};
struct procpriv {
VTAILQ_ENTRY(procpriv) list;
const char *vmod;
};
/*--------------------------------------------------------------------*/
static void
......@@ -355,3 +361,28 @@ VCC_XrefTable(struct vcc *tl)
VCC_WalkSymbols(tl, vcc_xreftable, SYM_NONE);
Fc(tl, 0, "*/\n\n");
}
/*---------------------------------------------------------------------
* mark vmod as referenced, return NULL if not yet marked, vmod if marked
*/
const char *
vcc_MarkPriv(struct vcc *tl, struct procprivhead *head,
const char *vmod)
{
struct procpriv *pp;
AN(vmod);
VTAILQ_FOREACH(pp, head, list) {
if (pp->vmod == vmod)
return (vmod);
AN(strcmp(pp->vmod, vmod));
}
pp = TlAlloc(tl, sizeof *pp);
assert(pp != NULL);
pp->vmod = vmod;
VTAILQ_INSERT_TAIL(head, pp, list);
return (NULL);
}
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