[DTrace-devel] [PATCH v5 05/10] alloca: deref
Nick Alcock
nick.alcock at oracle.com
Thu Apr 14 13:26:01 UTC 2022
From: Kris Van Hees <kris.van.hees at oracle.com>
Dereferencing an alloca() pointer (identified via its parser taint) is a
matter of validating that it is suitably bounded and not null, then
converting it into an actual map_value pointer by adding the scratchmem
base to it.
But this is made a bit more complex because bounds validation involves
not only validation of the address but the access size, and there we
have two distinct sorts of derefs to deal with: non-lvalue derefs, like
*foo, for which the load is done at the time of dereferencing and the
size is known, and lvalue loads, like foo[10]=bar, where the size stored
is not known until after the deref is complete.
For non-lvalue derefs this is quite easy: adjust dt_cg_load so it tells
us the size of load it's generating an op for, and add a bounds check to
the DT_TOK_DEREF case in dt_cg_node. For lvalue derefs this is
trickier: at DT_TOK_DEREF codegen time we have no idea what size of
store will be carried out, and in fact dt_cg_node generates no code at
all to deref an lvalue store. The deref is carried out in
dt_cg_store_val, which has to grow a special case for a store to a
writable lvalue node whose child is a deref with the DT_NF_ALLOCA flag
turned on. (This combination is generated by the compiler for lvalue
stores, so is completely stereotyped and safe to rely on). When this
case fires we can do a bounds-check just like the one done for reads.
We can also add a lot of tests and flip off XFAIL for a few pre-existing
ones, now that alloca and dereferencing of allocations both work.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/dt_cg.c | 185 ++++++++++++++++--
libdtrace/dt_parser.c | 18 +-
test/unittest/dif/alloca.d | 3 +-
.../alloca/err.D_ALLOCA_INCOMPAT.ternary.d | 26 +++
.../alloca/err.D_ALLOCA_INCOMPAT.ternary.r | 2 +
...rr.D_ALLOCA_INCOMPAT.var-clash-non-first.d | 28 +++
...rr.D_ALLOCA_INCOMPAT.var-clash-non-first.r | 2 +
.../alloca/err.D_ALLOCA_INCOMPAT.var-clash.d | 30 +++
.../alloca/err.D_ALLOCA_INCOMPAT.var-clash.r | 2 +
.../alloca/err.alloca-crossing-clauses.d | 31 +++
.../alloca/err.alloca-crossing-clauses.r | 3 +
.../alloca/err.alloca-load-before-bottom.d | 26 +++
.../alloca/err.alloca-load-before-bottom.r | 3 +
.../funcs/alloca/err.alloca-load-beyond-top.d | 28 +++
.../funcs/alloca/err.alloca-load-beyond-top.r | 3 +
.../alloca/err.alloca-load-crossing-bottom.d | 25 +++
.../alloca/err.alloca-load-crossing-bottom.r | 3 +
.../alloca/err.alloca-null-deref-lvalue.d | 29 +++
.../alloca/err.alloca-null-deref-lvalue.r | 3 +
.../funcs/alloca/err.alloca-null-deref.d | 27 +++
.../funcs/alloca/err.alloca-null-deref.r | 3 +
.../alloca/err.alloca-store-before-bottom.d | 26 +++
.../alloca/err.alloca-store-before-bottom.r | 3 +
.../alloca/err.alloca-store-beyond-top.d | 28 +++
.../alloca/err.alloca-store-beyond-top.r | 3 +
.../alloca/err.alloca-store-crossing-bottom.d | 26 +++
.../alloca/err.alloca-store-crossing-bottom.r | 3 +
.../funcs/alloca/tst.alloca-alignment.d | 34 ++++
.../alloca/tst.alloca-crossing-clauses.d | 33 ++++
.../funcs/alloca/tst.alloca-overtainting.sh | 35 ++++
....alloca-store-load-aliasing-arith-bottom.d | 29 +++
....alloca-store-load-aliasing-arith-bottom.r | 1 +
.../tst.alloca-store-load-aliasing-arith.d | 29 +++
.../alloca/tst.alloca-store-load-bottom.d | 27 +++
.../alloca/tst.alloca-store-load-idx-1.d | 27 +++
.../funcs/alloca/tst.alloca-store-load-top.d | 27 +++
.../alloca/tst.alloca0-after-alloca-load.d | 28 +++
.../funcs/alloca/tst.alloca0-after-alloca.d | 26 +++
test/unittest/funcs/alloca/tst.alloca0-load.d | 27 +++
.../funcs/alloca/tst.alloca0-values.sh | 34 ++++
test/unittest/funcs/alloca/tst.alloca0.d | 25 +++
test/unittest/funcs/alloca/tst.ternary.d | 27 +++
.../funcs/err.D_ALLOCA_SIZE.big_alloca.d | 24 +++
.../funcs/err.D_ALLOCA_SIZE.big_alloca.r | 2 +
test/unittest/funcs/err.badalloca.r | 3 +
test/unittest/funcs/err.badalloca.r.p | 3 +
test/unittest/funcs/err.badalloca2.d | 3 +-
test/unittest/funcs/err.badalloca2.r | 6 +-
...st.ValidPointer2.d => err.AllocaOverrun.d} | 11 +-
test/unittest/pointers/err.AllocaOverrun.r | 3 +
test/unittest/pointers/tst.ValidPointer1.d | 1 -
...CA_INCOMPAT.alloca-postinc-instantiation.d | 21 ++
...CA_INCOMPAT.alloca-postinc-instantiation.r | 2 +
.../tst.alloca-postinc-instantiation.d | 46 +++++
54 files changed, 1069 insertions(+), 34 deletions(-)
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.d
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.r
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.d
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.r
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.d
create mode 100644 test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-crossing-clauses.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-before-bottom.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-beyond-top.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-null-deref.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-null-deref.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-before-bottom.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-beyond-top.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.d
create mode 100644 test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
create mode 100644 test/unittest/funcs/alloca/tst.alloca-alignment.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca-crossing-clauses.d
create mode 100755 test/unittest/funcs/alloca/tst.alloca-overtainting.sh
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.r
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-bottom.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-idx-1.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca-store-load-top.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca0-after-alloca-load.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca0-after-alloca.d
create mode 100644 test/unittest/funcs/alloca/tst.alloca0-load.d
create mode 100755 test/unittest/funcs/alloca/tst.alloca0-values.sh
create mode 100644 test/unittest/funcs/alloca/tst.alloca0.d
create mode 100644 test/unittest/funcs/alloca/tst.ternary.d
create mode 100644 test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.d
create mode 100644 test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.r
create mode 100644 test/unittest/funcs/err.badalloca.r
create mode 100755 test/unittest/funcs/err.badalloca.r.p
rename test/unittest/pointers/{tst.ValidPointer2.d => err.AllocaOverrun.d} (62%)
create mode 100644 test/unittest/pointers/err.AllocaOverrun.r
create mode 100644 test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.d
create mode 100644 test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.r
create mode 100644 test/unittest/predicates/tst.alloca-postinc-instantiation.d
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index eaf8d6028275..5c28d23f3eb3 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -890,6 +890,73 @@ dt_cg_tstring_free(dt_pcb_t *pcb, dt_node_t *dnp)
}
}
+/*
+ * Validate sized access from an alloca pointer value.
+ *
+ * pos + size < top <=> pos < top - size
+ */
+static void
+dt_cg_alloca_access_check(dt_irlist_t *dlp, dt_regset_t *drp, int reg,
+ int isreg, ssize_t size)
+{
+ int scratchsize = yypcb->pcb_hdl->dt_options[DTRACEOPT_SCRATCHSIZE];
+ uint_t lbl_illval = dt_irlist_label(dlp);
+ uint_t lbl_base_ok = dt_irlist_label(dlp);
+ uint_t lbl_ok = dt_irlist_label(dlp);
+
+ dt_regset_xalloc(drp, BPF_REG_0);
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_FP, DT_STK_DCTX));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_0, DCTX_MST));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_0, DMST_SCRATCH_TOP));
+
+ emit(dlp, BPF_BRANCH_IMM(BPF_JSLT, reg, 8, lbl_illval));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JSGE, reg, scratchsize, lbl_illval));
+ emit(dlp, BPF_BRANCH_REG(BPF_JLT, reg, BPF_REG_0, lbl_base_ok));
+ emitl(dlp, lbl_illval,
+ BPF_NOP());
+ dt_cg_probe_error(yypcb, DTRACEFLT_BADADDR, DT_ISREG, reg);
+
+ emitl(dlp, lbl_base_ok,
+ BPF_NOP());
+
+ if (isreg)
+ emit(dlp, BPF_ALU64_REG(BPF_SUB, BPF_REG_0, size));
+ else
+ emit(dlp, BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, size));
+
+ emit(dlp, BPF_BRANCH_REG(BPF_JLE, reg, BPF_REG_0, lbl_ok));
+
+ dt_cg_probe_error(yypcb, DTRACEFLT_BADSIZE, isreg, size);
+
+ emitl(dlp, lbl_ok,
+ BPF_NOP());
+ dt_regset_free(drp, BPF_REG_0);
+}
+
+/*
+ * Convert an access-checked alloca pointer value into an actual scratchmem
+ * pointer.
+ */
+static void
+dt_cg_alloca_ptr(dt_irlist_t *dlp, dt_regset_t *drp, int dreg, int sreg)
+{
+ int reg = dreg;
+
+ if (dreg == sreg) {
+ if ((reg = dt_regset_alloc(drp)) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+ }
+
+ emit(dlp, BPF_LOAD(BPF_DW, reg, BPF_REG_FP, DT_STK_DCTX));
+ emit(dlp, BPF_LOAD(BPF_DW, reg, reg, DCTX_SCRATCHMEM));
+ emit(dlp, BPF_ALU64_REG(BPF_ADD, reg, sreg));
+
+ if (dreg == sreg) {
+ emit(dlp, BPF_MOV_REG(dreg, reg));
+ dt_regset_free(drp, reg);
+ }
+}
+
static const uint_t ldstw[] = {
0,
BPF_B, BPF_H, 0, BPF_W,
@@ -925,6 +992,7 @@ dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
dt_regset_t *drp = pcb->pcb_regs;
uint_t off;
size_t size;
+ int not_null = 0;
/*
* Special case for aggregations: we store the aggregation id. We
@@ -936,9 +1004,24 @@ dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
emit(dlp, BPF_MOV_IMM(dnp->dn_reg, dnp->dn_ident->di_id));
size = sizeof(dnp->dn_ident->di_id);
} else {
- dt_cg_node(dnp, &pcb->pcb_ir, drp);
+ dt_cg_node(dnp, dlp, drp);
dt_node_diftype(dtp, dnp, &vtype);
size = vtype.dtdt_size;
+
+ /*
+ * A DEREF of a REF node does not get resolved in dt_cg_node()
+ * because the ref node already holds the pointer. But for
+ * alloca pointers, that will be the offset into scratchmem so
+ * we still need to turn it into a real pointer here.
+ */
+ if (dnp->dn_kind == DT_NODE_OP1 &&
+ dnp->dn_op == DT_TOK_DEREF && (dnp->dn_flags & DT_NF_REF) &&
+ (dnp->dn_child->dn_flags & DT_NF_ALLOCA)) {
+ dt_cg_alloca_access_check(dlp, drp, dnp->dn_reg,
+ DT_ISIMM, size);
+ dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg, dnp->dn_reg);
+ not_null = 1;
+ }
}
if (kind == DTRACEACT_USYM ||
@@ -977,7 +1060,8 @@ dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
} else if (dt_node_is_string(dnp)) {
size_t strsize = pcb->pcb_hdl->dt_options[DTRACEOPT_STRSIZE];
- dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
+ if (!not_null)
+ dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
TRACE_REGSET("store_val(): Begin ");
off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, kind, size + 1,
@@ -1011,7 +1095,8 @@ dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
off = dt_rec_add(dtp, dt_cg_fill_gap, kind, size, 2, pfp, arg);
TRACE_REGSET("store_val(): Begin ");
- dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
+ if (!not_null)
+ dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
if (dt_regset_xalloc_args(drp) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
@@ -1972,7 +2057,7 @@ dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
* user=1 sign=1 size=4 => binary index 11011 = decimal index 27
*/
static uint_t
-dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
+dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type, ssize_t *ret_size)
{
#if 1
ctf_encoding_t e;
@@ -1994,6 +2079,9 @@ dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
"size %ld when passed by value\n", (long)size);
}
+ if (ret_size)
+ *ret_size = size;
+
return ldstw[size];
#else
static const uint_t ops[] = {
@@ -2033,6 +2121,9 @@ dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
if (dnp->dn_flags & DT_NF_USERLAND)
size |= 0x10;
+ if (ret_size)
+ *ret_size = size;
+
return ops[size];
#endif
}
@@ -2059,9 +2150,10 @@ dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, dst->dn_reg, DCTX_GVARS));
/* load the variable value or address */
- if (dst->dn_flags & DT_NF_REF)
+ if (dst->dn_flags & DT_NF_REF) {
+ assert(!(dst->dn_flags & DT_NF_ALLOCA));
emit(dlp, BPF_ALU64_IMM(BPF_ADD, dst->dn_reg, idp->di_offset));
- else {
+ } else {
size_t size = dt_node_type_size(dst);
assert(size > 0 && size <= 8 &&
@@ -2300,7 +2392,7 @@ dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
* r1 |= r2
*/
/* FIXME: Does not handle userland */
- emit(dlp, BPF_LOAD(dt_cg_load(dst, fp, m.ctm_type), r1, dst->dn_reg, 0));
+ emit(dlp, BPF_LOAD(dt_cg_load(dst, fp, m.ctm_type, NULL), r1, dst->dn_reg, 0));
dt_cg_setx(dlp, r2, cmask);
emit(dlp, BPF_ALU64_REG(BPF_AND, r1, r2));
dt_cg_setx(dlp, r2, fmask);
@@ -2315,9 +2407,9 @@ dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
static void
dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
{
- ctf_encoding_t e;
- size_t size;
- int reg;
+ ctf_encoding_t e;
+ size_t size;
+ int dreg = dst->dn_reg;
/*
* If we're loading a bit-field, the size of our store is found by
@@ -2330,21 +2422,44 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
else
size = dt_node_type_size(dst);
+ /*
+ * If we're loading a writable non-alloca lvalue, and it's a
+ * dereference, and *its* child is an alloca pointer, then this is a
+ * dereferenced alloca pointer and needs bounds-checking (which could
+ * not be done at deref time due to not knowing the size of the write).
+ */
+ if (dst->dn_flags & DT_NF_WRITABLE && dst->dn_flags & DT_NF_LVALUE
+ && dst->dn_op == DT_TOK_DEREF && dst->dn_child->dn_flags & DT_NF_ALLOCA) {
+ assert(!(dst->dn_flags & DT_NF_BITFIELD));
+
+ if ((dreg = dt_regset_alloc(drp)) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+ dt_cg_alloca_access_check(dlp, drp, dst->dn_reg,
+ DT_ISIMM, size);
+ dt_cg_alloca_ptr(dlp, drp, dreg, dst->dn_reg);
+ }
+
if (src->dn_flags & DT_NF_REF)
- dt_cg_memcpy(dlp, drp, dst->dn_reg, src->dn_reg, size);
+ dt_cg_memcpy(dlp, drp, dreg, src->dn_reg, size);
else {
+ int sreg;
+
if (dst->dn_flags & DT_NF_BITFIELD)
- reg = dt_cg_field_set(src, dlp, drp, dst);
+ sreg = dt_cg_field_set(src, dlp, drp, dst);
else
- reg = src->dn_reg;
+ sreg = src->dn_reg;
assert(size > 0 && size <= 8 && (size & (size - 1)) == 0);
- emit(dlp, BPF_STORE(ldstw[size], dst->dn_reg, 0, reg));
+ emit(dlp, BPF_STORE(ldstw[size], dreg, 0, sreg));
- if (dst->dn_flags & DT_NF_BITFIELD)
- dt_regset_free(drp, reg);
+ if (sreg != src->dn_reg)
+ dt_regset_free(drp, sreg);
}
+
+ if (dreg != dst->dn_reg)
+ dt_regset_free(drp, dreg);
}
/*
@@ -2608,7 +2723,20 @@ dt_cg_store_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
TRACE_REGSET(" store_var: Begin");
- /* Associative (global or TLS) array */
+ /*
+ * Stores of DT_NF_NONALLOCA nodes into identifiers with DT_IDFLG_ALLOCA
+ * set indicate that an identifier has been reused for both alloca and
+ * non-alloca purposes. Block this since it prevents us knowing whether
+ * to apply an offset to pointers loaded from this identifier.
+ */
+ if (dnp->dn_flags & DT_NF_ALLOCA && idp->di_flags & DT_IDFLG_NONALLOCA) {
+ xyerror(D_ALLOCA_INCOMPAT, "%s: cannot reuse the "
+ "same identifier for both alloca and "
+ "non-alloca allocations\n",
+ idp->di_name);
+ }
+
+ /* Associative (global or TLS) array. Cannot be in alloca space. */
if (idp->di_kind == DT_IDENT_ARRAY) {
dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
@@ -4680,6 +4808,8 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
if (!(dnp->dn_flags & DT_NF_REF)) {
uint_t ubit;
+ uint_t op;
+ ssize_t size;
/*
* Save and restore DT_NF_USERLAND across dt_cg_load():
@@ -4691,9 +4821,22 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
(dnp->dn_child->dn_flags & DT_NF_USERLAND);
dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
+ op = dt_cg_load(dnp, ctfp, dnp->dn_type, &size);
+
+ /*
+ * If the child is an alloca pointer, bounds-check it
+ * now.
+ */
+ if (dnp->dn_child->dn_flags & DT_NF_ALLOCA) {
+ assert(!(dnp->dn_flags & DT_NF_ALLOCA));
+ dt_cg_alloca_access_check(dlp, drp, dnp->dn_reg,
+ DT_ISIMM, size);
+ dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg,
+ dnp->dn_reg);
+ }
/* FIXME: Does not handled signed or userland */
- emit(dlp, BPF_LOAD(dt_cg_load(dnp, ctfp, dnp->dn_type), dnp->dn_reg, dnp->dn_reg, 0));
+ emit(dlp, BPF_LOAD(op, dnp->dn_reg, dnp->dn_reg, 0));
dnp->dn_flags &= ~DT_NF_USERLAND;
dnp->dn_flags |= ubit;
@@ -4850,7 +4993,8 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
(dnp->dn_left->dn_flags & DT_NF_USERLAND);
/* FIXME: Does not handle signed and userland */
- emit(dlp, BPF_LOAD(dt_cg_load(dnp, ctfp, m.ctm_type), dnp->dn_left->dn_reg, dnp->dn_left->dn_reg, 0));
+ emit(dlp, BPF_LOAD(dt_cg_load(dnp, ctfp, m.ctm_type, NULL),
+ dnp->dn_left->dn_reg, dnp->dn_left->dn_reg, 0));
dnp->dn_flags &= ~DT_NF_USERLAND;
dnp->dn_flags |= ubit;
@@ -4961,7 +5105,8 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
if (!(dnp->dn_flags & DT_NF_REF)) {
/* FIXME: NO signed or userland yet */
- emit(dlp, BPF_LOAD(dt_cg_load(dnp, ctfp, dnp->dn_type), dnp->dn_reg, dnp->dn_reg, 0));
+ emit(dlp, BPF_LOAD(dt_cg_load(dnp, ctfp, dnp->dn_type, NULL),
+ dnp->dn_reg, dnp->dn_reg, 0));
}
break;
}
diff --git a/libdtrace/dt_parser.c b/libdtrace/dt_parser.c
index 6e7409cc5f24..4377bb06a480 100644
--- a/libdtrace/dt_parser.c
+++ b/libdtrace/dt_parser.c
@@ -3153,6 +3153,10 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
if (cp->dn_flags & DT_NF_ALLOCA)
dt_cook_taint_alloca(dnp, NULL, cp);
+ else if (cp->dn_kind == DT_NODE_OP1 &&
+ cp->dn_op == DT_TOK_DEREF &&
+ (cp->dn_child->dn_flags & DT_NF_ALLOCA))
+ dt_cook_taint_alloca(dnp, NULL, cp->dn_child);
break;
case DT_TOK_SIZEOF:
@@ -3778,9 +3782,14 @@ asgn_common:
if (lp->dn_kind == DT_NODE_VAR)
lp_idp = lp->dn_ident;
+ /*
+ * Transfer alloca taint. Stores of non-alloca, non-literal-0
+ * values turn on DT_IDFLG_NONALLOCA to prevent this identifier
+ * from being used for alloca storage anywhere in the program.
+ */
if (rp->dn_flags & DT_NF_ALLOCA)
dt_cook_taint_alloca(lp, lp_idp, rp);
- else if (lp_idp)
+ else if (lp_idp && !(rp->dn_kind == DT_NODE_INT && rp->dn_value == 0))
lp_idp->di_flags |= DT_IDFLG_NONALLOCA;
dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
@@ -4020,9 +4029,14 @@ asgn_common:
dnp->dn_args = rp;
dnp->dn_list = NULL;
+ /*
+ * Transfer alloca taint. Stores of non-alloca, non-literal-0
+ * values turn on DT_IDFLG_NONALLOCA to prevent this identifier
+ * from being used for alloca storage anywhere in the program.
+ */
if (dnp->dn_args->dn_flags & DT_NF_ALLOCA)
dt_cook_taint_alloca(dnp, idp, dnp->dn_args);
- else
+ else if (dnp->dn_kind != DT_NODE_INT || dnp->dn_value != 0)
idp->di_flags |= DT_IDFLG_NONALLOCA;
dt_node_free(lp);
diff --git a/test/unittest/dif/alloca.d b/test/unittest/dif/alloca.d
index 9051ebbab7ed..c080acd2984a 100644
--- a/test/unittest/dif/alloca.d
+++ b/test/unittest/dif/alloca.d
@@ -1,6 +1,5 @@
-/* @@xfail: dtv2 */
BEGIN
{
- self->a = alloca(1024);
+ this->a = alloca(256);
exit(0);
}
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.d b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.d
new file mode 100644
index 000000000000..8de49be05b0f
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: ternary conditionals with alloca and non-alloca branches
+ * cannot be assigned to variables.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = (char *) alloca(1);
+ a = (a == NULL) ? (char *) 50 : a;
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.r b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.r
new file mode 100644
index 000000000000..c117d44a081f
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.ternary.d: [D_ALLOCA_INCOMPAT] line 20: ternary conditional with alloca and non-alloca branches cannot be assigned to a variable
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.d b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.d
new file mode 100644
index 000000000000..ace3fd3aa824
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: the same variable cannot be reused for alloca and
+ * non-alloca pointers, even in different clauses.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ b = (char *) &`max_pfn;
+ a = b + 5;
+}
+
+BEGIN
+{
+ a = (char *) alloca(1);
+ trace(a);
+ exit(0);
+}
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.r b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.r
new file mode 100644
index 000000000000..73ed28ba011b
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash-non-first.d: [D_ALLOCA_INCOMPAT] line 23: a: cannot reuse the same identifier for both alloca and non-alloca allocations
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.d b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.d
new file mode 100644
index 000000000000..fe9e274985d1
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.d
@@ -0,0 +1,30 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: the same variable cannot be reused for alloca and
+ * non-alloca pointers, even in different clauses.
+ * You can't fake it out by assigning NULL in between.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = (char *) alloca(1);
+}
+
+BEGIN
+{
+ b = (char *) &`max_pfn;
+ a = NULL;
+ a = b + 5;
+ trace(a);
+ exit(0);
+}
diff --git a/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.r b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.r
new file mode 100644
index 000000000000..ed642dc71f27
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/alloca/err.D_ALLOCA_INCOMPAT.var-clash.d: [D_ALLOCA_INCOMPAT] line 23: a: cannot reuse the same identifier for both alloca and non-alloca allocations
diff --git a/test/unittest/funcs/alloca/err.alloca-crossing-clauses.d b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.d
new file mode 100644
index 000000000000..eaadc40a533d
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.d
@@ -0,0 +1,31 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: alloca does not live beyond clause boundaries.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(1);
+ *s = 'a';
+}
+
+BEGIN
+{
+ trace(*s);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
\ No newline at end of file
diff --git a/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
new file mode 100644
index 000000000000..f5ff855de001
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-before-bottom.d b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.d
new file mode 100644
index 000000000000..9eeafc0f11f6
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Loads before the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(15);
+ trace(s[-1]);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-beyond-top.d b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.d
new file mode 100644
index 000000000000..b121179cfdf7
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Loads from beyond the top of alloca()ed memory fail.
+ * (Small overreads will often succeed due to alignment
+ * guarantees. This one should always fail.)
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(15);
+ trace(s[16]);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.d b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.d
new file mode 100644
index 000000000000..8208ea5e134e
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.d
@@ -0,0 +1,25 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Loads crossing the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (int *)alloca(10);
+ trace(s[-1]);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.d b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.d
new file mode 100644
index 000000000000..97d13f12a482
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.d
@@ -0,0 +1,29 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: You can't dereference a nullified alloca pointer via an lvalue,
+ * even if the resulting address is merely almost null.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+#pragma D option scratchsize=51
+
+BEGIN
+{
+ s = (char *) alloca(10);
+ s = NULL;
+ s[50] = 4;
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref.d b/test/unittest/funcs/alloca/err.alloca-null-deref.d
new file mode 100644
index 000000000000..77ee730651cd
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: You can't dereference a nullified alloca pointer.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *) alloca(10);
+ s = NULL;
+ *s = 4;
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref.r b/test/unittest/funcs/alloca/err.alloca-null-deref.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-before-bottom.d b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.d
new file mode 100644
index 000000000000..c0e5e4e0256b
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Stores before the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(15);
+ s[-1] = 65;
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-beyond-top.d b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.d
new file mode 100644
index 000000000000..a47024ac6c96
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Stores to beyond the top of alloca()ed memory fail.
+ * (Small overreads will often succeed due to alignment
+ * guarantees. This one should always fail.)
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(15);
+ s[16] = 65;
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.d b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.d
new file mode 100644
index 000000000000..b4dc5a4c56e7
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Stores crossing the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (int *)alloca(15);
+ s[-1] = 65;
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/tst.alloca-alignment.d b/test/unittest/funcs/alloca/tst.alloca-alignment.d
new file mode 100644
index 000000000000..22e6e5ce9fdc
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-alignment.d
@@ -0,0 +1,34 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: alloca() allocations are suitably aligned for any native datatype.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = alloca(1);
+ b = alloca(1);
+ trace((uint64_t) b);
+ trace("\n");
+ trace((uint64_t) a);
+ trace("\n");
+ trace((uint64_t) b - (uint64_t) a);
+ trace("\n");
+ trace(sizeof (uint64_t));
+ trace("\n");
+ exit((uint64_t) b - (uint64_t) a != sizeof (uint64_t));
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-crossing-clauses.d b/test/unittest/funcs/alloca/tst.alloca-crossing-clauses.d
new file mode 100644
index 000000000000..91409ec33781
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-crossing-clauses.d
@@ -0,0 +1,33 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: alloca does not live beyond clause boundaries; allocas in
+ * subsequent clauses reuse the same addresses.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(1);
+ *s = 'a';
+}
+
+BEGIN
+{
+ s2 = (char *)alloca(1);
+ *s2 = 'b';
+ exit(s == s2 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
\ No newline at end of file
diff --git a/test/unittest/funcs/alloca/tst.alloca-overtainting.sh b/test/unittest/funcs/alloca/tst.alloca-overtainting.sh
new file mode 100755
index 000000000000..3d4d64bae9fd
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-overtainting.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+tmpfile=${tmpdir:-/tmp}/tst.alloca0-overtainting.$$
+
+$dtrace $dt_flags -xtree=4 -s /dev/stdin > $tmpfile 2>&1 <<EOT
+BEGIN
+{
+ bar = alloca(10);
+ trace(bar);
+ exit(0);
+}
+EOT
+
+grep -q 'FUNC trace.*ALLOCA' $tmpfile
+status=$?
+
+rm $tmpfile
+
+if [[ $status -gt 0 ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.d b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.d
new file mode 100644
index 000000000000..b6b2b737ea2f
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.d
@@ -0,0 +1,29 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: You can still use a pointer to alloca'ed memory after it has been
+ * modified such that it no longer points there, as long as the
+ * access ends up dereferencing alloca'd memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(10);
+ j = s - 1;
+ j[1] = 65;
+ exit(s[0] == 65 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.r b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.r
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith-bottom.r
@@ -0,0 +1 @@
+
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith.d b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith.d
new file mode 100644
index 000000000000..291052a888d7
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-aliasing-arith.d
@@ -0,0 +1,29 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: It is possible to store to and load from alloca'ed memory
+ * via a pointer modified to still point in there.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(1);
+ s = (char *)alloca(10);
+ j = s - 1;
+ j[1] = 65;
+ exit(s[0] == 65 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-bottom.d b/test/unittest/funcs/alloca/tst.alloca-store-load-bottom.d
new file mode 100644
index 000000000000..61d2eea3f9ae
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-bottom.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: It is possible to store to and load from the bottom byte of
+ * alloca()'d memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(10);
+ s[0] = 65;
+ exit(s[0] == 65 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-idx-1.d b/test/unittest/funcs/alloca/tst.alloca-store-load-idx-1.d
new file mode 100644
index 000000000000..77a454a8cab4
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-idx-1.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: It is possible to store to and load from byte 1 of alloca()'d
+ * memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(10);
+ s[1] = 65;
+ exit(s[1] == 65 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-store-load-top.d b/test/unittest/funcs/alloca/tst.alloca-store-load-top.d
new file mode 100644
index 000000000000..48b50044fec8
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-store-load-top.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: It is possible to store to and load from the top byte of
+ * alloca()'d memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = (char *)alloca(10);
+ s[9] = 65;
+ exit(s[9] == 65 ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca0-after-alloca-load.d b/test/unittest/funcs/alloca/tst.alloca0-after-alloca-load.d
new file mode 100644
index 000000000000..904f5ce3e0f6
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca0-after-alloca-load.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling alloca(0) is valid and subsequent calls will give the
+ * same result, after a previous non-zero alloca, even when one
+ * alloca(0) is stored to and loaded from a variable.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = alloca(10);
+ s = alloca(0);
+ exit(alloca(0) == s ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca0-after-alloca.d b/test/unittest/funcs/alloca/tst.alloca0-after-alloca.d
new file mode 100644
index 000000000000..62e79b906c9a
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca0-after-alloca.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling alloca(0) is valid and subsequent calls will give the
+ * same result, after a previous non-zero alloca.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = alloca(10);
+ exit(alloca(0) == alloca(0) ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca0-load.d b/test/unittest/funcs/alloca/tst.alloca0-load.d
new file mode 100644
index 000000000000..508c2c971731
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca0-load.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling alloca(0) is valid and subsequent calls will give the
+ * same result, even when one is stored to and loaded from a
+ * variable.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ s = alloca(0);
+ exit(alloca(0) == s ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca0-values.sh b/test/unittest/funcs/alloca/tst.alloca0-values.sh
new file mode 100755
index 000000000000..fce42423843e
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca0-values.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+tmpfile=${tmpdir:-/tmp}/tst.alloca0-values.$$
+
+$dtrace $dt_flags -o $tmpfile -s /dev/stdin <<EOT
+BEGIN {
+ trace(alloca(0));
+ trace(s = alloca(0));
+ trace(s);
+ trace(alloca(0));
+
+ exit(0);
+}
+EOT
+
+awk '/:BEGIN/ && $2 == $3 && $3 == $4 && $4 == $5 { exit(0); }
+ /:BEGIN/ { print; exit(1); }' $tmpfile
+
+status=$?
+rm $tmpfile
+
+exit $status
diff --git a/test/unittest/funcs/alloca/tst.alloca0.d b/test/unittest/funcs/alloca/tst.alloca0.d
new file mode 100644
index 000000000000..027cb72831a6
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca0.d
@@ -0,0 +1,25 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Calling alloca(0) is valid and subsequent calls will give the
+ * same result.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ exit(alloca(0) == alloca(0) ? 0 : 1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.ternary.d b/test/unittest/funcs/alloca/tst.ternary.d
new file mode 100644
index 000000000000..c871495d1cb0
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.ternary.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: ternary conditionals with alloca and non-alloca branches
+ * can be used for things other than variable assignment.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = (char *) alloca(1);
+ trace((a == NULL) ? (char *) 50 : a);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.d b/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.d
new file mode 100644
index 000000000000..6305001df4de
--- /dev/null
+++ b/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.d
@@ -0,0 +1,24 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION:
+ * Too-large alloca() allocations are a compile-time error.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ *
+ */
+
+#pragma D option quiet
+
+#pragma D option scratchsize=1024
+
+BEGIN
+{
+ ptr = alloca(1025);
+ exit(1);
+}
diff --git a/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.r b/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.r
new file mode 100644
index 000000000000..0822290ff1b5
--- /dev/null
+++ b/test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/err.D_ALLOCA_SIZE.big_alloca.d: [D_ALLOCA_SIZE] line 22: alloca(1025) size larger than scratchsize 1024
diff --git a/test/unittest/funcs/err.badalloca.r b/test/unittest/funcs/err.badalloca.r
new file mode 100644
index 000000000000..302243300d82
--- /dev/null
+++ b/test/unittest/funcs/err.badalloca.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 4 (ID NNN: profile:::tick-1): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/err.badalloca.r.p b/test/unittest/funcs/err.badalloca.r.p
new file mode 100755
index 000000000000..d7a88a39626d
--- /dev/null
+++ b/test/unittest/funcs/err.badalloca.r.p
@@ -0,0 +1,3 @@
+#!/bin/sed -f
+
+s/(ID [0-9]*/(ID NNN/g
diff --git a/test/unittest/funcs/err.badalloca2.d b/test/unittest/funcs/err.badalloca2.d
index fc3e2c25143e..72331e9e80f0 100644
--- a/test/unittest/funcs/err.badalloca2.d
+++ b/test/unittest/funcs/err.badalloca2.d
@@ -1,10 +1,9 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
diff --git a/test/unittest/funcs/err.badalloca2.r b/test/unittest/funcs/err.badalloca2.r
index 4392318d2456..65ace8669383 100644
--- a/test/unittest/funcs/err.badalloca2.r
+++ b/test/unittest/funcs/err.badalloca2.r
@@ -1,6 +1,2 @@
- FUNCTION:NAME
- :ERROR
-
-- @@stderr --
-dtrace: script 'test/unittest/funcs/err.badalloca2.d' matched 2 probes
-dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): out of scratch space in action #2 at DIF offset 16
+dtrace: failed to compile script test/unittest/funcs/err.badalloca2.d: line 20: alloca(18446744073709551615) size larger than scratchsize 256
diff --git a/test/unittest/pointers/tst.ValidPointer2.d b/test/unittest/pointers/err.AllocaOverrun.d
similarity index 62%
rename from test/unittest/pointers/tst.ValidPointer2.d
rename to test/unittest/pointers/err.AllocaOverrun.d
index ca8c0dcf7578..16654e0ba030 100644
--- a/test/unittest/pointers/tst.ValidPointer2.d
+++ b/test/unittest/pointers/err.AllocaOverrun.d
@@ -4,10 +4,12 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
- * ASSERTION: Demonstrating valid memory access.
+ * ASSERTION: Demonstrating invalid memory access.
+ * (Solaris never implemented bounds checking, so accesses, even
+ * writes, beyond the alloca()ed region but within scratch space
+ * were expected to succeed. They obviously should not.)
*
* SECTION: Pointers and Arrays/Pointers and Addresses
*
@@ -27,3 +29,8 @@ BEGIN
exit(0);
}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/pointers/err.AllocaOverrun.r b/test/unittest/pointers/err.AllocaOverrun.r
new file mode 100644
index 000000000000..187543b63023
--- /dev/null
+++ b/test/unittest/pointers/err.AllocaOverrun.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/pointers/tst.ValidPointer1.d b/test/unittest/pointers/tst.ValidPointer1.d
index 95a2baa7250e..9dd3fdf473ba 100644
--- a/test/unittest/pointers/tst.ValidPointer1.d
+++ b/test/unittest/pointers/tst.ValidPointer1.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: Demonstrating valid memory access.
diff --git a/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.d b/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.d
new file mode 100644
index 000000000000..f1d2dffbb5ec
--- /dev/null
+++ b/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: alloca assignment to variables in predicates doesn't
+ * interfere with alloca/nonalloca compatibility checking.
+ */
+
+#pragma D option quiet
+
+BEGIN / (new++ == 0) ? bar = alloca(10) : bar /
+{
+ trace(new);
+ bar = &`max_pfn;
+}
+
+ERROR { exit(1); }
diff --git a/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.r b/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.r
new file mode 100644
index 000000000000..2bdf1a87f97c
--- /dev/null
+++ b/test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/predicates/err.D_ALLOCA_INCOMPAT.alloca-postinc-instantiation.d: [D_ALLOCA_INCOMPAT] line 15: bar: cannot reuse the same identifier for both alloca and non-alloca allocations
diff --git a/test/unittest/predicates/tst.alloca-postinc-instantiation.d b/test/unittest/predicates/tst.alloca-postinc-instantiation.d
new file mode 100644
index 000000000000..e411713628ef
--- /dev/null
+++ b/test/unittest/predicates/tst.alloca-postinc-instantiation.d
@@ -0,0 +1,46 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: alloca assignment to variables in predicates works and
+ * instantiates the variable in the clause body too, just
+ * as already happens for postfix increment. You can store
+ * and load from it.
+ */
+
+#pragma D option quiet
+
+BEGIN / (new++ == 0) ? bar = alloca(10) : bar /
+{
+ trace(new);
+ trace(bar);
+ b = (int *) ((long) bar + 1 - 1);
+ *b = 0;
+ b_value = *b;
+}
+
+BEGIN / new == 0 /
+{
+ trace("new is still zero");
+ exit(1);
+}
+
+BEGIN / b_value == 0 / { exit(0); }
+
+BEGIN / b == 0 /
+{
+ printf("b stayed zero");
+ exit(1);
+}
+
+BEGIN
+{
+ printf("*b is %x, not zero", b_value);
+ exit(1);
+}
+
+ERROR { exit(1); }
--
2.35.1
More information about the DTrace-devel
mailing list