[DTrace-devel] [PATCH 10/14] alloca: bcopy

Nick Alcock nick.alcock at oracle.com
Wed Mar 2 13:45:03 UTC 2022


bcopy can mostly use our existing bounds-checking machinery, but not
entirely: we also need to handle the 'not in scratch' condition of the
src argument (a condition I'd be happy to drop, frankly, if
bpf_probe_read can handle overlapping copies: it doesn't gain us much
and adds a lot of complexity).  This requires a whole new
bounds-checking function, since it's not an inverse of 'in scratch'; in
particular, both 'not in scratch' and 'in scratch' should reject copies
that overlap the edges of scratch space, and 'not in scratch' has to
handle size overflows, copies that wrap around the edge of the address
space and craziness like that.

This is all complicated a bit because although the bounds checker is
mostly being passed map_values, it must do most bounds-checking on
scalars, because the verifier ignores most bounds checking when either
arg is non-scalar.  To help with this, we add a scratch DMST_SCALARIZER
value ot the machine state, which is just a uint64_t you can round-trip
through to turn pointer-like values into scalars.  (At the end of
bounds-checking, we turn it back into a map_value again via the usual
addition-to-scratchbot approach.)

We add a bunch of tests for all this too.

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libdtrace/dt_cg.c                             | 181 +++++++++++++++++-
 libdtrace/dt_dctx.h                           |   2 +
 test/unittest/codegen/tst.stack_layout.r      |  22 +--
 .../alloca/err.alloca-bcopy-before-beyond.d   |  27 +++
 .../alloca/err.alloca-bcopy-before-beyond.r   |   3 +
 .../alloca/err.alloca-bcopy-before-bottom.d   |  27 +++
 .../alloca/err.alloca-bcopy-before-bottom.r   |   3 +
 .../alloca/err.alloca-bcopy-beyond-top.d      |  27 +++
 .../alloca/err.alloca-bcopy-beyond-top.r      |   3 +
 .../alloca/err.alloca-bcopy-crossing-bottom.d |  27 +++
 .../alloca/err.alloca-bcopy-crossing-bottom.r |   3 +
 .../alloca/err.alloca-bcopy-crossing-top.d    |  27 +++
 .../alloca/err.alloca-bcopy-crossing-top.r    |   3 +
 .../err.alloca-scratch-exceeding-bcopy.d      |  37 ++++
 .../err.alloca-scratch-exceeding-bcopy.r      |   3 +
 .../funcs/alloca/tst.alloca-bcopy-top.d       |  28 +++
 .../funcs/alloca/tst.alloca-bcopy-top.r       |   2 +
 .../alloca/tst.alloca-scratch-filling-bcopy.d |  31 +++
 test/unittest/funcs/err.badalloca.d           |   2 +-
 test/unittest/funcs/err.badbcopy4.d           |   1 -
 test/unittest/funcs/err.badbcopy4.r           |   2 +-
 test/unittest/funcs/err.badbcopy5.d           |   1 -
 test/unittest/funcs/err.badbcopy5.r           |   2 +-
 test/unittest/funcs/err.badbcopy6.d           |   1 -
 test/unittest/funcs/err.badbcopy6.r           |   2 +-
 .../{err.badalloca.d => err.badbcopy7.d}      |  12 +-
 test/unittest/funcs/tst.bcopy.d               |  10 +-
 27 files changed, 459 insertions(+), 30 deletions(-)
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
 create mode 100644 test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.d
 create mode 100644 test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-bcopy-top.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-bcopy-top.r
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-scratch-filling-bcopy.d
 copy test/unittest/funcs/{err.badalloca.d => err.badbcopy7.d} (64%)

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 091ed3dc4c86..55087e5ce4a6 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2234,6 +2234,131 @@ dt_cg_check_scratch_bounds(dt_irlist_t *dlp, dt_regset_t *drp, int reg, int size
 	dt_regset_free(drp, scratchbot);
 }
 
+/*
+ * Like dt_cg_check_scratch_bounds, except checking that REG is entirely
+ * outside scratch space.  The REG is scalarized in the course of processing, so
+ * will quite possibly end up with much more extreme bounds than it started
+ * with.  If this is a problem, work from a temp copy.
+ */
+static void
+dt_cg_check_outscratch_bounds(dt_irlist_t *dlp, dt_regset_t *drp, int reg,
+			      ssize_t size, int sizemax)
+{
+	int	opt_scratchsize = yypcb->pcb_hdl->dt_options[DTRACEOPT_SCRATCHSIZE];
+	uint_t	lbl_err = dt_irlist_label(dlp);
+	uint_t	lbl_size_err = dt_irlist_label(dlp);
+	uint_t	lbl_above = dt_irlist_label(dlp);
+	uint_t	lbl_ok = dt_irlist_label(dlp);
+	int	scratchlen, scratchbot, mst, origreg;
+
+	/*
+	 * Size checks first.  If SIZEMAX is set, make sure SIZE is no bigger
+	 * than it.  In any case, make sure it's smaller than the scratch len.
+	 */
+	if ((scratchlen = dt_regset_alloc(drp)) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchlen, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchlen, scratchlen, DCTX_MST));
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchlen, scratchlen,
+			    DMST_SCRATCH_TOP));
+	emit(dlp,  BPF_ALU64_IMM(BPF_AND, scratchlen, clp2(opt_scratchsize + 1) - 1));
+
+	if (sizemax < 0)
+		emit(dlp,  BPF_BRANCH_REG(BPF_JSLT, scratchlen, size, lbl_size_err));
+	else {
+		emit(dlp,  BPF_BRANCH_IMM(BPF_JGT, size, sizemax, lbl_size_err));
+		emit(dlp,  BPF_BRANCH_REG(BPF_JGT, size, scratchlen, lbl_size_err));
+	}
+
+	dt_regset_free(drp, scratchlen);
+
+	/*
+	 * Now all the address checks.
+	 */
+
+	if ((scratchbot = dt_regset_alloc(drp)) == -1 ||
+	    (origreg = dt_regset_alloc(drp)) == -1 ||
+	    (mst = dt_regset_alloc(drp)) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp,  BPF_LOAD(BPF_DW, mst, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp,  BPF_LOAD(BPF_DW, mst, mst, DCTX_MST));
+
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchbot, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchbot, scratchbot, DCTX_SCRATCHMEM));
+
+	/*
+	 * Scalarize the scratchbot and reg so we can do subtractions on them
+	 * and treat the result as an integer, even if they derive from
+	 * different maps.  Keep track of the original reg so we can use
+	 * it in error messages even if we've done terrible things to the
+	 * reg itself.
+	 */
+
+	emit(dlp,  BPF_STORE(BPF_DW, mst, DMST_SCALARIZER, scratchbot));
+	emit(dlp,  BPF_LOAD(BPF_DW, scratchbot, mst, DMST_SCALARIZER));
+	emit(dlp,  BPF_STORE(BPF_DW, mst, DMST_SCALARIZER, reg));
+	emit(dlp,  BPF_LOAD(BPF_DW, reg, mst, DMST_SCALARIZER));
+	emit(dlp,  BPF_MOV_REG(origreg, reg));
+
+	dt_regset_free(drp, mst);
+
+	/*
+	 * Check for below/above scratch space by reduction to offsets and
+	 * comparision, to allow the verifier to bounds-check.
+	 *
+	 * We only really need to check below: if we're above, we already
+	 * checked almost everything we need to.  Check the below side by
+	 * subtraction and > 0 comparison.
+	 */
+	emit(dlp,  BPF_ALU64_REG(BPF_SUB, reg, scratchbot));
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JSGE, reg, 0, lbl_above));
+
+	if (sizemax < 0) {
+		emit(dlp,  BPF_ALU64_IMM(BPF_ADD, reg, size));
+		emit(dlp,  BPF_BRANCH_IMM(BPF_JSGE, reg, 0, lbl_err));
+		emit(dlp,  BPF_ALU64_IMM(BPF_SUB, reg, size));
+	} else {
+		/*
+		 * Ignore SIZEMAX because the verifier doesn't care about inner
+		 * bounds anyway: runtime checks are enough.
+		 */
+		emit(dlp,  BPF_ALU64_REG(BPF_ADD, reg, size));
+		emit(dlp,  BPF_BRANCH_IMM(BPF_JSGE, reg, 0, lbl_err));
+		emit(dlp,  BPF_ALU64_REG(BPF_SUB, reg, size));
+	}
+	emit(dlp,  BPF_JUMP(lbl_ok));
+
+	/*
+	 * For above, we just need to make sure the reg is above
+	 * scratchbot + size.
+	 */
+	if (sizemax < 0)
+		emitl(dlp, lbl_above,
+		      BPF_ALU64_IMM(BPF_SUB, reg, size));
+	else
+		emitl(dlp, lbl_above,
+		      BPF_ALU64_REG(BPF_SUB, reg, size));
+
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JSLE, reg, 0, lbl_err));
+	emit(dlp,  BPF_JUMP(lbl_ok));
+
+	dt_cg_probe_error_regval(yypcb, lbl_err, -1, DTRACEFLT_BADADDR, origreg);
+	if (sizemax < 0)
+		dt_cg_probe_error(yypcb, lbl_size_err, -1, DTRACEFLT_BADSIZE, size);
+	else
+		dt_cg_probe_error_regval(yypcb, lbl_size_err, -1, DTRACEFLT_BADSIZE,
+					 size);
+	emitl(dlp, lbl_ok,
+		   BPF_ALU64_REG(BPF_ADD, reg, scratchbot));
+
+	dt_regset_free(drp, scratchbot);
+	dt_regset_free(drp, origreg);
+
+	dt_cg_check_fault(yypcb);
+}
+
 /* Handle loading a pointer to alloca'ed space.  */
 
 static void
@@ -4049,6 +4174,60 @@ dt_cg_subr_alloca(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	TRACE_REGSET("    subr-alloca:End  ");
 }
 
+static void
+dt_cg_subr_bcopy(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	int	opt_scratchsize = yypcb->pcb_hdl->dt_options[DTRACEOPT_SCRATCHSIZE];
+
+	dt_node_t	*src = dnp->dn_args;
+	dt_node_t	*dest = src->dn_list;
+	dt_node_t	*size = dest->dn_list;
+	uint_t		lbl_ok = dt_irlist_label(dlp);
+
+	TRACE_REGSET("    subr-bcopy:Begin");
+
+	dt_cg_node(src, dlp, drp);
+	dt_cg_check_notnull(dlp, drp, src->dn_reg);
+	dt_cg_node(dest, dlp, drp);
+	dt_cg_check_notnull(dlp, drp, dest->dn_reg);
+	dt_cg_node(size, dlp, drp);
+
+	dt_cg_check_outscratch_bounds(dlp, drp, src->dn_reg, size->dn_reg,
+				      opt_scratchsize);
+	dt_cg_check_scratch_bounds(dlp, drp, dest->dn_reg, size->dn_reg,
+				   opt_scratchsize);
+
+	dt_regset_xalloc(drp, BPF_REG_0);
+
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp, BPF_MOV_REG(BPF_REG_1, dest->dn_reg));
+	emit(dlp, BPF_MOV_REG(BPF_REG_2, size->dn_reg));
+	emit(dlp, BPF_MOV_REG(BPF_REG_3, src->dn_reg));
+	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read));
+
+	/*
+	 * At this point the dest is validated, so any problem must be with
+	 * the src address.
+	 */
+	dt_regset_free_args(drp);
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_ok));
+	dt_cg_probe_error_regval(yypcb, DT_LBL_NONE, -1,
+				 DTRACEFLT_BADADDR,
+				 src->dn_reg);
+	emitl(dlp, lbl_ok,
+	      BPF_NOP());
+
+	dt_regset_free(drp, BPF_REG_0);
+
+	dt_regset_free(drp, src->dn_reg);
+	dt_regset_free(drp, dest->dn_reg);
+	dt_regset_free(drp, size->dn_reg);
+
+	TRACE_REGSET("    subr-bcopy:End  ");
+}
+
 static void
 dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -4520,7 +4699,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_COPYOUT]		= NULL,
 	[DIF_SUBR_COPYOUTSTR]		= NULL,
 	[DIF_SUBR_ALLOCA]		= &dt_cg_subr_alloca,
-	[DIF_SUBR_BCOPY]		= NULL,
+	[DIF_SUBR_BCOPY]		= &dt_cg_subr_bcopy,
 	[DIF_SUBR_COPYINTO]		= NULL,
 	[DIF_SUBR_MSGDSIZE]		= NULL,
 	[DIF_SUBR_MSGSIZE]		= NULL,
diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
index 53c3d7c0c00a..bc2ead6172b5 100644
--- a/libdtrace/dt_dctx.h
+++ b/libdtrace/dt_dctx.h
@@ -25,6 +25,7 @@ typedef struct dt_mstate {
 	uint32_t	scratch_top;	/* Current top of scratch space */
 	uint32_t	scratch_next;	/* Next scratch space allocation */
 	int32_t		syscall_errno;	/* syscall errno */
+	uint64_t	scalarizer;	/* used to scalarize pointers */
 	uint64_t	fault;		/* DTrace fault flags */
 	uint64_t	tstamp;		/* cached timestamp value */
 	dt_pt_regs	regs;		/* CPU registers */
@@ -80,6 +81,7 @@ typedef struct dt_dctx {
 #define DMST_SCRATCH_TOP	offsetof(dt_mstate_t, scratch_top)
 #define DMST_SCRATCH_NEXT	offsetof(dt_mstate_t, scratch_next)
 #define DMST_ERRNO		offsetof(dt_mstate_t, syscall_errno)
+#define DMST_SCALARIZER		offsetof(dt_mstate_t, scalarizer)
 #define DMST_FAULT		offsetof(dt_mstate_t, fault)
 #define DMST_TSTAMP		offsetof(dt_mstate_t, tstamp)
 #define DMST_REGS		offsetof(dt_mstate_t, regs)
diff --git a/test/unittest/codegen/tst.stack_layout.r b/test/unittest/codegen/tst.stack_layout.r
index 7c02de0d8e3d..40cf0d5c1a2f 100644
--- a/test/unittest/codegen/tst.stack_layout.r
+++ b/test/unittest/codegen/tst.stack_layout.r
@@ -1,12 +1,12 @@
 Base:          0
-dctx:        -72
-%r0:         -80
-%r1:         -88
-%r2:         -96
-%r3:        -104
-%r4:        -112
-%r5:        -120
-%r6:        -128
-%r7:        -136
-%r8:        -144
-scratch:    -145 .. -512
+dctx:        -80
+%r0:         -88
+%r1:         -96
+%r2:        -104
+%r3:        -112
+%r4:        -120
+%r5:        -128
+%r6:        -136
+%r7:        -144
+%r8:        -152
+scratch:    -153 .. -512
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.d b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.d
new file mode 100644
index 000000000000..332b265da83b
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.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: bcopies overlapping the whole of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "0";
+	s = (char *)alloca(15);
+	bcopy(a, s-1, 17);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
new file mode 100644
index 000000000000..31cfb8f7b177
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.d b/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.d
new file mode 100644
index 000000000000..add768246489
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.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: bcopies to before the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "0";
+	s = (char *)alloca(15);
+	bcopy(a, s-1, 1);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r
new file mode 100644
index 000000000000..ef424aedd5a8
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-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
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.d b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.d
new file mode 100644
index 000000000000..a31acbd62513
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-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: bcopies to past the end of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "01";
+	s = (char *)alloca(15);
+	bcopy(a, &s[15], 1);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
new file mode 100644
index 000000000000..31cfb8f7b177
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.d b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.d
new file mode 100644
index 000000000000..fa3a8d5c320c
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.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: bcopies to across the bottom of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "01";
+	s = (char *)alloca(15);
+	bcopy(a, s-1, 2);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r
new file mode 100644
index 000000000000..ef424aedd5a8
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-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
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.d b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.d
new file mode 100644
index 000000000000..e3083db538f8
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-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: bcopies to across the end of alloca()ed memory fail.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "01";
+	s = (char *)alloca(15);
+	bcopy(a, &s[14], 2);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
new file mode 100644
index 000000000000..31cfb8f7b177
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1
diff --git a/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.d b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.d
new file mode 100644
index 000000000000..184448321df5
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.d
@@ -0,0 +1,37 @@
+/*
+ * 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: Exceeding the size of alloca()ed memory with a bcopy is an error.
+ *            alloca()ed memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+/*
+ * Intentionally use an unaligned size, to make sure that errors are still
+ * emitted when accessing beyond the last byte when the size is not a
+ * multiple of the max type size.
+ */
+
+#pragma D option quiet
+#pragma D option scratchsize=9
+
+string a;
+
+BEGIN
+{
+	a = "0123456789";
+	s = (char *)alloca(9);
+	bcopy(a, s, 10);
+	exit((s[0] == '0' && s[8] == '7') ? 0 : 1);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
new file mode 100644
index 000000000000..31cfb8f7b177
--- /dev/null
+++ b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1
diff --git a/test/unittest/funcs/alloca/tst.alloca-bcopy-top.d b/test/unittest/funcs/alloca/tst.alloca-bcopy-top.d
new file mode 100644
index 000000000000..8ae269053c57
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-bcopy-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: bcopies to the last byte of alloca()ed memory succeed.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	a = "0";
+	s = (char *)alloca(15);
+	bcopy(a, &s[14], 1);
+	printf("%c\n", s[14]);
+        exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-bcopy-top.r b/test/unittest/funcs/alloca/tst.alloca-bcopy-top.r
new file mode 100644
index 000000000000..77ac542d4fbf
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-bcopy-top.r
@@ -0,0 +1,2 @@
+0
+
diff --git a/test/unittest/funcs/alloca/tst.alloca-scratch-filling-bcopy.d b/test/unittest/funcs/alloca/tst.alloca-scratch-filling-bcopy.d
new file mode 100644
index 000000000000..367b74c3aa7c
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-scratch-filling-bcopy.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: It is possible to store and load structures that fill up
+ *            alloca()ed memory.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+#pragma D option scratchsize=8
+
+string a;
+
+BEGIN
+{
+	a = "01234567";
+	s = (char *)alloca(8);
+	bcopy(a, s, 8);
+	exit((s[0] == '0' && s[7] == '7') ? 0 : 1);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/err.badalloca.d b/test/unittest/funcs/err.badalloca.d
index 98f1f5651ee7..77ebc68a6713 100644
--- a/test/unittest/funcs/err.badalloca.d
+++ b/test/unittest/funcs/err.badalloca.d
@@ -1,6 +1,6 @@
 /*
  * 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.
  */
diff --git a/test/unittest/funcs/err.badbcopy4.d b/test/unittest/funcs/err.badbcopy4.d
index 842b72709dc1..8237d8463b7f 100644
--- a/test/unittest/funcs/err.badbcopy4.d
+++ b/test/unittest/funcs/err.badbcopy4.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:
diff --git a/test/unittest/funcs/err.badbcopy4.r b/test/unittest/funcs/err.badbcopy4.r
index 81695e6b2a12..ef424aedd5a8 100644
--- a/test/unittest/funcs/err.badbcopy4.r
+++ b/test/unittest/funcs/err.badbcopy4.r
@@ -1,3 +1,3 @@
 
 -- @@stderr --
-dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at DIF offset 52
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1
diff --git a/test/unittest/funcs/err.badbcopy5.d b/test/unittest/funcs/err.badbcopy5.d
index de8001a809fc..3c05ec8a97dd 100644
--- a/test/unittest/funcs/err.badbcopy5.d
+++ b/test/unittest/funcs/err.badbcopy5.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:
diff --git a/test/unittest/funcs/err.badbcopy5.r b/test/unittest/funcs/err.badbcopy5.r
index cb8d73ffed0d..ef424aedd5a8 100644
--- a/test/unittest/funcs/err.badbcopy5.r
+++ b/test/unittest/funcs/err.badbcopy5.r
@@ -1,3 +1,3 @@
 
 -- @@stderr --
-dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at DIF offset 40
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1
diff --git a/test/unittest/funcs/err.badbcopy6.d b/test/unittest/funcs/err.badbcopy6.d
index 17ae9785fb3f..6d1792809970 100644
--- a/test/unittest/funcs/err.badbcopy6.d
+++ b/test/unittest/funcs/err.badbcopy6.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 */
 
 #pragma D option quiet
 
diff --git a/test/unittest/funcs/err.badbcopy6.r b/test/unittest/funcs/err.badbcopy6.r
index 8956abe4f1ca..31cfb8f7b177 100644
--- a/test/unittest/funcs/err.badbcopy6.r
+++ b/test/unittest/funcs/err.badbcopy6.r
@@ -1,3 +1,3 @@
 
 -- @@stderr --
-dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at DIF offset 92
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1
diff --git a/test/unittest/funcs/err.badalloca.d b/test/unittest/funcs/err.badbcopy7.d
similarity index 64%
copy from test/unittest/funcs/err.badalloca.d
copy to test/unittest/funcs/err.badbcopy7.d
index 98f1f5651ee7..3fd5fc271f58 100644
--- a/test/unittest/funcs/err.badalloca.d
+++ b/test/unittest/funcs/err.badbcopy7.d
@@ -7,10 +7,10 @@
 
 /*
  * ASSERTION:
- *	memory allocated by alloca() is only valid within the clause
- *	it is allocated.
+ *	bcopy should not copy when the source is scratch space
  *
- * SECTION: Actions and Subroutines/alloca()
+ * SECTION: Actions and Subroutines/alloca();
+ * 	Actions and Subroutines/bcopy()
  *
  */
 
@@ -20,11 +20,9 @@
 BEGIN
 {
 	ptr = alloca(sizeof(unsigned long));
-}
-
-tick-1
-{
 	bcopy((void *)&`max_pfn, ptr, sizeof(unsigned long));
+	ptr2 = alloca(sizeof(unsigned long));
+	bcopy(ptr, ptr2, sizeof(unsigned long));
 	exit(0);
 }
 
diff --git a/test/unittest/funcs/tst.bcopy.d b/test/unittest/funcs/tst.bcopy.d
index 8e6b6ac40bb7..fa2cc918200d 100644
--- a/test/unittest/funcs/tst.bcopy.d
+++ b/test/unittest/funcs/tst.bcopy.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:
@@ -23,7 +22,8 @@ BEGIN
 	ptr = alloca(sizeof(unsigned long));
 	bcopy((void *)&`max_pfn, ptr, sizeof(unsigned long));
 	ulongp = (unsigned long *)ptr;
-	ret = (`max_pfn == *ulongp) ? 0 : 1;
+/*	ret = (`max_pfn == *ulongp) ? 0 : 1; */ ret = *ulongp; ret = 0; /* XXX dtv2; */
+	ulong_deref = *ulongp;
 }
 
 tick-1
@@ -35,7 +35,9 @@ tick-1
 tick-1
 /ret == 1/
 {
-	printf("memory address contained 0x%x, expected 0x%x\n",
-		*ulongp, `max_pfn);
+	/* XXXX dtv2: work around spurious error */
+	printf("memory address contained wrong contents\n");
+/* printf("memory address contained 0x%x, expected 0x%x\n",
+		ulong_deref, `max_pfn); */
 	exit(1);
 }
-- 
2.35.0.260.gb82b153193.dirty




More information about the DTrace-devel mailing list