Add a bitmask tracking SUB calls to detect recursions

To allow dynamic SUB calls, we need to check for recursions at
runtime, reflecting the compile time recursion check.

We create a bitmask to note each dynamically called SUB by its unique
number. To check for recursions, we only need to test if the
respective bit for the sub number is already set.

We only conduct this check if the track_call argument of
vcl_call_method() is true. By setting this argument to the number of
SUB references, we enable call tracking only for VCLs with dynamic SUB
references (when (struct VCL_conf).nsub is non-zero).

VCC already guarantees that static calls are loop free - so loops can
only be introduced through dynamic SUB references.

Call tracking with a bitmask was suggested by phk
parent 8551b1f5
......@@ -39,9 +39,11 @@
#include "vcl.h"
#include "vtim.h"
#include "vbm.h"
#include "cache_director.h"
#include "cache_vcl.h"
#include "vcc_interface.h"
/*--------------------------------------------------------------------*/
......@@ -444,10 +446,13 @@ VRT_VCL_Allow_Discard(struct vclref **refp)
static void
vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
void *specific, unsigned method, vcl_func_f *func)
void *specific, unsigned method, vcl_func_f *func, unsigned track_call)
{
uintptr_t aws;
uintptr_t rws = 0, aws;
struct vrt_ctx ctx;
struct vbitmap *vbm;
void *p;
size_t sz;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
INIT_OBJ(&ctx, VRT_CTX_MAGIC);
......@@ -468,6 +473,15 @@ vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
assert(ctx.now != 0);
ctx.specific = specific;
ctx.method = method;
if (track_call > 0) {
rws = WS_Snapshot(wrk->aws);
sz = VBITMAP_SZ(track_call);
p = WS_Alloc(wrk->aws, sz);
// No use to attempt graceful failure, all VCL calls will fail
AN(p);
vbm = vbit_init(p, sz);
ctx.called = vbm;
}
aws = WS_Snapshot(wrk->aws);
wrk->cur_method = method;
wrk->seen_methods |= method;
......@@ -484,6 +498,8 @@ vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
* wrk->aws, but they can reserve and return from it.
*/
assert(aws == WS_Snapshot(wrk->aws));
if (rws != 0)
WS_Reset(wrk->aws, rws);
}
#define VCL_MET_MAC(func, upper, typ, bitmap) \
......@@ -496,7 +512,7 @@ VCL_##func##_method(struct vcl *vcl, struct worker *wrk, \
CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC); \
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); \
vcl_call_method(wrk, req, bo, specific, \
VCL_MET_ ## upper, vcl->conf->func##_func); \
VCL_MET_ ## upper, vcl->conf->func##_func, vcl->conf->nsub);\
AN((1U << wrk->handling) & bitmap); \
}
......
......@@ -332,6 +332,8 @@ struct vrt_ctx {
* synth+error: struct vsb *
*/
void *specific;
/* if present, vbitmap of called subs */
void *called;
};
#define VRT_CTX const struct vrt_ctx *ctx
......
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