[DTrace-devel] [PATCH 06/12] Assigning 0 to any dynamic variable should delete it

Kris Van Hees kris.van.hees at oracle.com
Fri Jan 5 05:29:14 UTC 2024


Assigning 0 to a scalar dynamic variable deletes it from storage, but
due to type compatibility rules, this cannot be used to delete dynamic
variables of struct of union type.

Add a special case for assigning a literal 0 constant value to any
dynamic variable to signify deleting the variable from storage.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                             | 18 +++++--
 libdtrace/dt_parser.c                         | 12 ++++-
 .../assocs/tst.store_zero_deletes_struct.d    | 50 +++++++++++++++++++
 .../assocs/tst.store_zero_deletes_struct.r    |  1 +
 .../assocs/tst.store_zero_deletes_union.d     | 50 +++++++++++++++++++
 .../assocs/tst.store_zero_deletes_union.r     |  1 +
 .../tvar/tst.store_zero_deletes_struct.d      | 42 ++++++++++++++++
 .../tvar/tst.store_zero_deletes_struct.r      |  1 +
 .../tvar/tst.store_zero_deletes_union.d       | 42 ++++++++++++++++
 .../tvar/tst.store_zero_deletes_union.r       |  1 +
 10 files changed, 214 insertions(+), 4 deletions(-)
 create mode 100644 test/unittest/assocs/tst.store_zero_deletes_struct.d
 create mode 100644 test/unittest/assocs/tst.store_zero_deletes_struct.r
 create mode 100644 test/unittest/assocs/tst.store_zero_deletes_union.d
 create mode 100644 test/unittest/assocs/tst.store_zero_deletes_union.r
 create mode 100644 test/unittest/variables/tvar/tst.store_zero_deletes_struct.d
 create mode 100644 test/unittest/variables/tvar/tst.store_zero_deletes_struct.r
 create mode 100644 test/unittest/variables/tvar/tst.store_zero_deletes_union.d
 create mode 100644 test/unittest/variables/tvar/tst.store_zero_deletes_union.r

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index d9d56f0a..615ebdbf 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3627,15 +3627,26 @@ dt_cg_store_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
 
 	/* First handle dvars. */
 	if (idp->di_kind == DT_IDENT_ARRAY || idp->di_flags & DT_IDFLG_TLS) {
-		uint_t	lbl_done = dt_irlist_label(dlp);
-
-		uint_t	lbl_notnull = dt_irlist_label(dlp);
+		uint_t		lbl_done = dt_irlist_label(dlp);
+		uint_t		lbl_notnull = dt_irlist_label(dlp);
+		dt_node_t	*rp = dnp->dn_right;
 
 		dt_cg_prep_dvar_args(dnp, dlp, drp, idp, 1, &fnp);
 
 		dt_regset_xalloc(drp, BPF_REG_0);
 		emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp);
 		dt_regset_free_args(drp);
+
+		/*
+		 * Special case: a store of a literal 0 causes the dynamic
+		 * variable to be deleted by the BPF function called above, so
+		 * nothing is left to be done.
+		 */
+		if (rp->dn_kind == DT_NODE_INT && rp->dn_value == 0) {
+			dt_regset_free(drp, BPF_REG_0);
+			goto dvar_deleted;
+		}
+
 		emit(dlp,  BPF_BRANCH_IMM(BPF_JEQ, dnp->dn_reg, 0, lbl_done));
 		emit(dlp,  BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, 0, lbl_notnull));
 		emit(dlp,  BPF_MOV_IMM(BPF_REG_0, 0));
@@ -3669,6 +3680,7 @@ dt_cg_store_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
 		emitl(dlp, lbl_done,
 			   BPF_NOP());
 
+dvar_deleted:
 		TRACE_REGSET("    store_var: End  ");
 
 		return;
diff --git a/libdtrace/dt_parser.c b/libdtrace/dt_parser.c
index f6addc78..92580f1d 100644
--- a/libdtrace/dt_parser.c
+++ b/libdtrace/dt_parser.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2024, 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.
  */
@@ -3791,6 +3791,16 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
 		if (dt_node_is_argcompat(lp, rp))
 			goto asgn_common;
 
+		/*
+		 * Special case: assigning a literal 0 is allowed for dynamic
+		 * variables because that is used to delete them from storage.
+		 */
+		if (lp->dn_kind == DT_NODE_VAR &&
+		    (lp->dn_ident->di_kind == DT_IDENT_ARRAY ||
+		     (lp->dn_ident->di_flags & DT_IDFLG_TLS)) &&
+		    rp->dn_kind == DT_NODE_INT && rp->dn_value == 0)
+			goto asgn_common;
+
 		xyerror(D_OP_INCOMPAT,
 		    "operands have incompatible types: \"%s\" %s \"%s\"\n",
 		    dt_node_type_name(lp, n1, sizeof(n1)), opstr(op),
diff --git a/test/unittest/assocs/tst.store_zero_deletes_struct.d b/test/unittest/assocs/tst.store_zero_deletes_struct.d
new file mode 100644
index 00000000..11dbd1ba
--- /dev/null
+++ b/test/unittest/assocs/tst.store_zero_deletes_struct.d
@@ -0,0 +1,50 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2024, 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: Storing 0 into an associate array element removes it from
+ *	      storage, making room for another element, even for structs.
+ *
+ * SECTION: Variables/Associative Arrays
+ */
+
+/*
+ * We need enough storage to store 4 dynamic variables.  Each dynamic variable
+ * will require 20 bytes of storage:
+ *	0..3   = Variable ID
+ *	4..7   = Index
+ *	8..15  = 0
+ *	16..19 = Value
+ */
+#pragma D option dynvarsize=80
+#pragma D option quiet
+
+this struct {
+    int a;
+} val;
+
+BEGIN
+{
+	this->val.a = 1;
+	a[1] = this->val;
+	this->val.a = 2;
+	a[2] = this->val;
+	this->val.a = 3;
+	a[3] = this->val;
+	a[1] = 0;
+	this->val.a = 4;
+	a[4] = this->val;
+	trace(a[2].a);
+	trace(a[3].a);
+	trace(a[4].a);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/assocs/tst.store_zero_deletes_struct.r b/test/unittest/assocs/tst.store_zero_deletes_struct.r
new file mode 100644
index 00000000..7b5813c6
--- /dev/null
+++ b/test/unittest/assocs/tst.store_zero_deletes_struct.r
@@ -0,0 +1 @@
+234
diff --git a/test/unittest/assocs/tst.store_zero_deletes_union.d b/test/unittest/assocs/tst.store_zero_deletes_union.d
new file mode 100644
index 00000000..3d43f373
--- /dev/null
+++ b/test/unittest/assocs/tst.store_zero_deletes_union.d
@@ -0,0 +1,50 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2024, 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: Storing 0 into an associate array element removes it from
+ *	      storage, making room for another element, even for unions.
+ *
+ * SECTION: Variables/Associative Arrays
+ */
+
+/*
+ * We need enough storage to store 4 dynamic variables.  Each dynamic variable
+ * will require 20 bytes of storage:
+ *	0..3   = Variable ID
+ *	4..7   = Index
+ *	8..15  = 0
+ *	16..19 = Value
+ */
+#pragma D option dynvarsize=80
+#pragma D option quiet
+
+this union {
+    int a;
+} val;
+
+BEGIN
+{
+	this->val.a = 1;
+	a[1] = this->val;
+	this->val.a = 2;
+	a[2] = this->val;
+	this->val.a = 3;
+	a[3] = this->val;
+	a[1] = 0;
+	this->val.a = 4;
+	a[4] = this->val;
+	trace(a[2].a);
+	trace(a[3].a);
+	trace(a[4].a);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/assocs/tst.store_zero_deletes_union.r b/test/unittest/assocs/tst.store_zero_deletes_union.r
new file mode 100644
index 00000000..7b5813c6
--- /dev/null
+++ b/test/unittest/assocs/tst.store_zero_deletes_union.r
@@ -0,0 +1 @@
+234
diff --git a/test/unittest/variables/tvar/tst.store_zero_deletes_struct.d b/test/unittest/variables/tvar/tst.store_zero_deletes_struct.d
new file mode 100644
index 00000000..fc73b3b9
--- /dev/null
+++ b/test/unittest/variables/tvar/tst.store_zero_deletes_struct.d
@@ -0,0 +1,42 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2024, 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: Storing 0 into a TLS variable removes it from storage, making
+ *	      room for another variable, even if it is a struct.
+ *
+ * SECTION: Variables/Thread-Local Variables
+ */
+
+#pragma D option quiet
+#pragma D option dynvarsize=15
+
+this struct {
+  int a;
+} val;
+
+BEGIN
+{
+	this->val.a = 1;
+	self->a = this->val;
+	this->val.a = 2;
+	self->b = this->val;
+	this->val.a = 3;
+	self->c = this->val;
+	self->a = 0;
+	this->val.a = 4;
+	self->d = this->val;
+	trace(self->b.a);
+	trace(self->c.a);
+	trace(self->d.a);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/variables/tvar/tst.store_zero_deletes_struct.r b/test/unittest/variables/tvar/tst.store_zero_deletes_struct.r
new file mode 100644
index 00000000..7b5813c6
--- /dev/null
+++ b/test/unittest/variables/tvar/tst.store_zero_deletes_struct.r
@@ -0,0 +1 @@
+234
diff --git a/test/unittest/variables/tvar/tst.store_zero_deletes_union.d b/test/unittest/variables/tvar/tst.store_zero_deletes_union.d
new file mode 100644
index 00000000..8abb851f
--- /dev/null
+++ b/test/unittest/variables/tvar/tst.store_zero_deletes_union.d
@@ -0,0 +1,42 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2024, 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: Storing 0 into a TLS variable removes it from storage, making
+ *	      room for another variable, even if it is a union.
+ *
+ * SECTION: Variables/Thread-Local Variables
+ */
+
+#pragma D option quiet
+#pragma D option dynvarsize=15
+
+this union {
+  int a;
+} val;
+
+BEGIN
+{
+	this->val.a = 1;
+	self->a = this->val;
+	this->val.a = 2;
+	self->b = this->val;
+	this->val.a = 3;
+	self->c = this->val;
+	self->a = 0;
+	this->val.a = 4;
+	self->d = this->val;
+	trace(self->b.a);
+	trace(self->c.a);
+	trace(self->d.a);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/variables/tvar/tst.store_zero_deletes_union.r b/test/unittest/variables/tvar/tst.store_zero_deletes_union.r
new file mode 100644
index 00000000..7b5813c6
--- /dev/null
+++ b/test/unittest/variables/tvar/tst.store_zero_deletes_union.r
@@ -0,0 +1 @@
+234
-- 
2.42.0




More information about the DTrace-devel mailing list