[DTrace-devel] [PATCH v4 08/10] cg: support null pointers in ternary conditionals

Nick Alcock nick.alcock at oracle.com
Tue Apr 12 10:59:07 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>
---
 libdtrace/dt_cg.c                             | 188 ++++++++++++++++--
 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.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 +++++
 53 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
 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 227536a8a99e..b1b498b30085 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -24,6 +24,9 @@
 #include <dt_string.h>
 #include <bpf_asm.h>
 
+#define DT_ISIMM	0
+#define DT_ISREG	1
+
 static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
 
 /*
@@ -887,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,
@@ -922,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
@@ -933,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 ||
@@ -974,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,
@@ -1008,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);
@@ -1969,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;
@@ -1991,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[] = {
@@ -2030,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
 }
@@ -2056,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 &&
@@ -2297,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);
@@ -2312,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
@@ -2327,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);
 }
 
 /*
@@ -2603,7 +2721,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);
 
@@ -4675,6 +4806,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():
@@ -4686,9 +4819,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;
@@ -4845,7 +4991,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;
@@ -4956,7 +5103,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 b8f37d8d6b17..e850cd55a65e 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] */
@@ -4022,9 +4031,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..ca6c894991bd
--- /dev/null
+++ b/test/unittest/funcs/err.badalloca.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 4 (ID 113831: profile:::tick-1): invalid address ({ptr}) in action #1 at BPF pc NNN
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