[DTrace-devel] [PATCH 33/47] Fix value of post-increment expressions

Kris Van Hees kris.van.hees at oracle.com
Sun May 3 20:17:54 PDT 2020


When using a post-increment (or post-decrement) on a variable of any
kind, the expression should evaluate to the old value.

E.g. trace(this->x++) generates (WRONG):

	lddw	%r8, [%fp-80]		! load old value
	add	%r8, 1			! increment
	stdw	[%fp-80], %r8		! store new value
	(%r8 is used as value, which is old value + 1)

while instead it should generate (CORRECT):

	lddw	%r8, [%fp-80]		! load old value
	mov	%r7, 1			! load increment
	add	%r7, %r8		! add old value to increment
	stdw	[%fp-80], %r7		! store new value
	(%r8 is used as value, which is old value)

Tests are included in this patch for both pre-increment and
post-increment of each of the three variable kinds.  Since the code
generator uses the same logic for increment and decrement, testing
just one is sufficient.

Orabug: 31220528
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                             | 19 ++++++++++++-------
 test/unittest/codegen/tst.post_inc_gvar_val.d | 17 +++++++++++++++++
 test/unittest/codegen/tst.post_inc_gvar_val.r |  5 +++++
 test/unittest/codegen/tst.post_inc_lvar_val.d | 17 +++++++++++++++++
 test/unittest/codegen/tst.post_inc_lvar_val.r |  5 +++++
 test/unittest/codegen/tst.post_inc_tvar_val.d | 17 +++++++++++++++++
 test/unittest/codegen/tst.post_inc_tvar_val.r |  5 +++++
 test/unittest/codegen/tst.pre_inc_gvar_val.d  | 17 +++++++++++++++++
 test/unittest/codegen/tst.pre_inc_gvar_val.r  |  5 +++++
 test/unittest/codegen/tst.pre_inc_lvar_val.d  | 17 +++++++++++++++++
 test/unittest/codegen/tst.pre_inc_lvar_val.r  |  5 +++++
 test/unittest/codegen/tst.pre_inc_tvar_val.d  | 17 +++++++++++++++++
 test/unittest/codegen/tst.pre_inc_tvar_val.r  |  5 +++++
 13 files changed, 144 insertions(+), 7 deletions(-)
 create mode 100644 test/unittest/codegen/tst.post_inc_gvar_val.d
 create mode 100644 test/unittest/codegen/tst.post_inc_gvar_val.r
 create mode 100644 test/unittest/codegen/tst.post_inc_lvar_val.d
 create mode 100644 test/unittest/codegen/tst.post_inc_lvar_val.r
 create mode 100644 test/unittest/codegen/tst.post_inc_tvar_val.d
 create mode 100644 test/unittest/codegen/tst.post_inc_tvar_val.r
 create mode 100644 test/unittest/codegen/tst.pre_inc_gvar_val.d
 create mode 100644 test/unittest/codegen/tst.pre_inc_gvar_val.r
 create mode 100644 test/unittest/codegen/tst.pre_inc_lvar_val.d
 create mode 100644 test/unittest/codegen/tst.pre_inc_lvar_val.r
 create mode 100644 test/unittest/codegen/tst.pre_inc_tvar_val.d
 create mode 100644 test/unittest/codegen/tst.pre_inc_tvar_val.r

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 60037b9a..8f1120bd 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -1347,7 +1347,7 @@ dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 
 	/*
-	 * If we are modifying a variable, generate an stv instruction from
+	 * If we are modifying a variable, generate a store instruction for
 	 * the variable specified by the identifier.  If we are storing to a
 	 * memory address, generate code again for the left-hand side using
 	 * DT_NF_REF to get the address, and then generate a store to it.
@@ -1382,7 +1382,7 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
 	struct bpf_insn instr;
 	ctf_id_t type;
 	ssize_t size = 1;
-	int nreg;
+	int oreg, nreg;
 
 	if (dt_node_is_pointer(dnp)) {
 		type = ctf_type_resolve(ctfp, dnp->dn_type);
@@ -1392,27 +1392,32 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
 
 	dt_cg_node(dnp->dn_child, dlp, drp);
 	dnp->dn_reg = dnp->dn_child->dn_reg;
+	oreg = dnp->dn_reg;
 
-	if ((nreg = dt_regset_alloc(drp)) == -1)
+	nreg = dt_regset_alloc(drp);
+	if (nreg == -1)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
 
-	instr = BPF_ALU64_IMM(op, dnp->dn_reg, size);
+	instr = BPF_MOV_IMM(nreg, size);
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+	instr = BPF_ALU64_REG(op, nreg, dnp->dn_reg);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 
 	/*
-	 * If we are modifying a variable, generate an stv instruction from
+	 * If we are modifying a variable, generate a store instruction for
 	 * the variable specified by the identifier.  If we are storing to a
 	 * memory address, generate code again for the left-hand side using
 	 * DT_NF_REF to get the address, and then generate a store to it.
-	 * In both paths, we store the value from 'nreg' (the new value).
+	 * In both paths, we store the value from %r0 (the new value).
 	 */
 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
 
+		dnp->dn_reg = nreg;
 		dt_cg_store_var(dnp, dlp, drp, idp);
+		dnp->dn_reg = oreg;
 	} else {
 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
-		int oreg = dnp->dn_reg;
 
 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
diff --git a/test/unittest/codegen/tst.post_inc_gvar_val.d b/test/unittest/codegen/tst.post_inc_gvar_val.d
new file mode 100644
index 00000000..6fa66b28
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_gvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that post-increment on an global variable evaluates to the
+ *            old value of the global variable.
+ */
+
+BEGIN
+{
+	trace(x++);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_gvar_val.r b/test/unittest/codegen/tst.post_inc_gvar_val.r
new file mode 100644
index 00000000..dbd0b8da
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_gvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_gvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.post_inc_lvar_val.d b/test/unittest/codegen/tst.post_inc_lvar_val.d
new file mode 100644
index 00000000..d340e578
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_lvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that post-increment on an local variable evaluates to the
+ *            old value of the local variable.
+ */
+
+BEGIN
+{
+	trace(this->x++);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_lvar_val.r b/test/unittest/codegen/tst.post_inc_lvar_val.r
new file mode 100644
index 00000000..e6e33861
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_lvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_lvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.post_inc_tvar_val.d b/test/unittest/codegen/tst.post_inc_tvar_val.d
new file mode 100644
index 00000000..f9c63910
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_tvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that post-increment on a TLS variable evaluates to the
+ *            old value of the TLS variable.
+ */
+
+BEGIN
+{
+	trace(self->x++);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_tvar_val.r b/test/unittest/codegen/tst.post_inc_tvar_val.r
new file mode 100644
index 00000000..2d19b737
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_tvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_tvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_gvar_val.d b/test/unittest/codegen/tst.pre_inc_gvar_val.d
new file mode 100644
index 00000000..0d7bca5e
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_gvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that pre-increment on an global variable evaluates to the
+ *	      new value of the global variable.
+ */
+
+BEGIN
+{
+	trace(++x);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_gvar_val.r b/test/unittest/codegen/tst.pre_inc_gvar_val.r
new file mode 100644
index 00000000..9625b369
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_gvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_gvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_lvar_val.d b/test/unittest/codegen/tst.pre_inc_lvar_val.d
new file mode 100644
index 00000000..65a2ecfc
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_lvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that pre-increment on an local variable evaluates to the
+ *            new value of the local variable.
+ */
+
+BEGIN
+{
+	trace(++this->x);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_lvar_val.r b/test/unittest/codegen/tst.pre_inc_lvar_val.r
new file mode 100644
index 00000000..1bca8c90
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_lvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_lvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_tvar_val.d b/test/unittest/codegen/tst.pre_inc_tvar_val.d
new file mode 100644
index 00000000..ee671591
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_tvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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: Test that pre-increment on an TLS variable evaluates to the
+ *            new value of the TLS variable.
+ */
+
+BEGIN
+{
+	trace(++self->x);
+	exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_tvar_val.r b/test/unittest/codegen/tst.pre_inc_tvar_val.r
new file mode 100644
index 00000000..d03ec6a2
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_tvar_val.r
@@ -0,0 +1,5 @@
+                   FUNCTION:NAME
+                          :BEGIN                 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_tvar_val.d' matched 1 probe
-- 
2.26.0




More information about the DTrace-devel mailing list