[DTrace-devel] [PATCH] Fix typecast

Kris Van Hees kris.van.hees at oracle.com
Mon Aug 1 19:15:21 UTC 2022


DTrace internally keeps integers basically in a 64-bit format.  Shorter,
signed integers are already sign-extended.

The current logic makes an error when an integer is extended and the
signedness changes.  It truncates the source and then extends.  E.g.,
consider a 1-byte source and 2-byte destination:

    signed?
    src dst  input  expected  currently

     N   Y    0xff   0x00ff       -1
     Y   N    0xff   0xffff      0xff

Note:

*) In the first case, no casting is even necessary.  If the integer
is being extended and it is unsigned, then higher-order bits can simply
be left alone.

*) In the second case, the signed input is supposed to be sign-extended
before truncating to the new size.  We currently truncate first, at the
smaller size.

Fix.  Add tests.

Notice that:

*) Casting constants like "var = (type) constant" is handled
   in the parser.

*) Casting variables like "var1 = (type) var2" is handled
   in the code generator.

This patch is a modified version of an earlier patch by Eugene Loh.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                       |  34 ++++----
 libdtrace/dt_parser.c                   |  14 ++--
 test/unittest/arithmetic/tst.cast-exp.d | 101 ++++++++++++++++++++++++
 test/unittest/arithmetic/tst.cast-exp.r |  43 ++++++++++
 4 files changed, 167 insertions(+), 25 deletions(-)
 create mode 100644 test/unittest/arithmetic/tst.cast-exp.d
 create mode 100644 test/unittest/arithmetic/tst.cast-exp.r

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 3e53c4bc..b40c9e48 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2515,30 +2515,19 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
 {
 	size_t srcsize;
 	size_t dstsize;
-	int n;
 
 	/* If the destination type is '@' (any type) we need not cast. */
 	if (dst->dn_ctfp == NULL && dst->dn_type == CTF_ERR)
 		return;
 
-	srcsize = dt_node_type_size(src);
-	dstsize = dt_node_type_size(dst);
-
-	if (dstsize < srcsize)
-		n = sizeof(uint64_t) * NBBY - dstsize * NBBY;
-	else
-		n = sizeof(uint64_t) * NBBY - srcsize * NBBY;
-
 	if (!dt_node_is_scalar(dst))
 		return;
 
-	if (n != 0 && (dstsize < srcsize ||
-	    (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {
-		emit(dlp, BPF_MOV_REG(dst->dn_reg, src->dn_reg));
-		emit(dlp, BPF_ALU64_IMM(BPF_LSH, dst->dn_reg, n));
-		emit(dlp, BPF_ALU64_IMM((dst->dn_flags & DT_NF_SIGNED) ? BPF_ARSH : BPF_RSH, dst->dn_reg, n));
-	} else if (dt_node_is_arith(dst) && dt_node_is_pointer(src) &&
-		   (src->dn_flags & DT_NF_ALLOCA)) {
+	srcsize = dt_node_type_size(src);
+	dstsize = dt_node_type_size(dst);
+
+	if (dt_node_is_arith(dst) && dt_node_is_pointer(src) &&
+	    (src->dn_flags & DT_NF_ALLOCA)) {
 		int mst;
 
 		if ((mst = dt_regset_alloc(drp)) == -1)
@@ -2550,6 +2539,19 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
 		emit(dlp,  BPF_LOAD(BPF_DW, dst->dn_reg, mst, DMST_SCALARIZER));
 
 		dt_regset_free(drp, mst);
+	} else {
+		int srcsigned = src->dn_flags & DT_NF_SIGNED;
+		int dstsigned = dst->dn_flags & DT_NF_SIGNED;
+
+		if (dst->dn_reg != src->dn_reg)
+			emit(dlp, BPF_MOV_REG(dst->dn_reg, src->dn_reg));
+
+		if ((!srcsigned && dstsigned) && srcsize == dstsize) {
+			int n = (sizeof(uint64_t) - dstsize) * NBBY;
+
+			emit(dlp, BPF_ALU64_IMM(BPF_LSH, dst->dn_reg, n));
+			emit(dlp, BPF_ALU64_IMM(BPF_ARSH, dst->dn_reg, n));
+		}
 	}
 }
 
diff --git a/libdtrace/dt_parser.c b/libdtrace/dt_parser.c
index 8cd4ec10..1625e887 100644
--- a/libdtrace/dt_parser.c
+++ b/libdtrace/dt_parser.c
@@ -2123,18 +2123,14 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
 	    dt_node_is_integer(lp)) {
 		size_t srcsize = dt_node_type_size(rp);
 		size_t dstsize = dt_node_type_size(lp);
+		int srcsigned = rp->dn_flags & DT_NF_SIGNED;
+		int dstsigned = lp->dn_flags & DT_NF_SIGNED;
 
-		if ((dstsize < srcsize) || ((lp->dn_flags & DT_NF_SIGNED) ^
-		    (rp->dn_flags & DT_NF_SIGNED))) {
-			int n = dstsize < srcsize ?
-			    (sizeof(uint64_t) * NBBY - dstsize * NBBY) :
-			    (sizeof(uint64_t) * NBBY - srcsize * NBBY);
+		if ((!srcsigned && dstsigned) && srcsize == dstsize) {
+			int n = (sizeof(uint64_t) - dstsize) * NBBY;
 
 			rp->dn_value <<= n;
-			if (lp->dn_flags & DT_NF_SIGNED)
-				rp->dn_value = (intmax_t)rp->dn_value >> n;
-			else
-				rp->dn_value = rp->dn_value >> n;
+			rp->dn_value = (intmax_t)rp->dn_value >> n;
 		}
 
 		dt_node_type_propagate(lp, rp);
diff --git a/test/unittest/arithmetic/tst.cast-exp.d b/test/unittest/arithmetic/tst.cast-exp.d
new file mode 100644
index 00000000..6939586b
--- /dev/null
+++ b/test/unittest/arithmetic/tst.cast-exp.d
@@ -0,0 +1,101 @@
+/*
+ * 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:  Integers are typecast correctly. (explicit)
+ *	       Compare results to a similar C program,
+ *	       albeit with the format string
+ *	       "%hhd %hd %d %lld %hhu %hu %u %llu\n".
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ */
+/* @@runtest-opts: -qC */
+
+signed char c;
+short s;
+int i;
+long long l;
+unsigned char C;
+unsigned short S;
+unsigned int I;
+unsigned long long L;
+
+#define TEST(x) \
+	c = (char)(x); \
+	s = (short)(x); \
+	i = (int)(x); \
+	l = (long long)(x); \
+	C = (unsigned char)(x); \
+	S = (unsigned short)(x); \
+	I = (unsigned int)(x); \
+	L = (unsigned long long)(x); \
+	printf("%d %d %d %d %d %d %d %d\n", c, s, i, l, C, S, I, L)
+
+BEGIN
+{
+	/* from scalar */
+	TEST(-2);
+	TEST(0xfffffffffffffffe);
+	TEST(0xfffffffe);
+	TEST(0xfffe);
+	TEST(0xfe);
+	TEST(2);
+	TEST(0x55);
+	TEST(0x5555);
+	TEST(0x55555555);
+	TEST(0x5555555555555555);
+
+	/* from char */
+	c = -2; TEST(c);
+	c = 0xfe; TEST(c);
+	c = 2; TEST(c);
+	c = 0x55; TEST(c);
+
+	/* from short */
+	s = -2; TEST(s);
+	s = 0xfffe; TEST(s);
+	s = 2; TEST(s);
+	s = 0x5555; TEST(s);
+
+	/* from int */
+	i = -2; TEST(i);
+	i = 0xfffffffe; TEST(i);
+	i = 2; TEST(i);
+	i = 0x55555555; TEST(i);
+
+	/* from long long */
+	l = -2; TEST(l);
+	l = 0xfffffffffffffffe; TEST(l);
+	l = 2; TEST(l);
+	l = 0x5555555555555555; TEST(l);
+
+	/* from unsigned char */
+	C = -2; TEST(C);
+	C = 0xfe; TEST(C);
+	C = 2; TEST(C);
+	C = 0x55; TEST(C);
+
+	/* from unsigned short */
+	S = -2; TEST(S);
+	S = 0xfffe; TEST(S);
+	S = 2; TEST(S);
+	S = 0x5555; TEST(S);
+
+	/* from unsigned int */
+	I = -2; TEST(I);
+	I = 0xfffffffe; TEST(I);
+	I = 2; TEST(I);
+	I = 0x55555555; TEST(I);
+
+	/* from unsigned long long */
+	L = -2; TEST(L);
+	L = 0xfffffffffffffffe; TEST(L);
+	L = 2; TEST(L);
+	L = 0x5555555555555555; TEST(L);
+
+	exit (0);
+}
diff --git a/test/unittest/arithmetic/tst.cast-exp.r b/test/unittest/arithmetic/tst.cast-exp.r
new file mode 100644
index 00000000..0ae3e3f1
--- /dev/null
+++ b/test/unittest/arithmetic/tst.cast-exp.r
@@ -0,0 +1,43 @@
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 4294967294 254 65534 4294967294 4294967294
+-2 -2 65534 65534 254 65534 65534 65534
+-2 254 254 254 254 254 254 254
+2 2 2 2 2 2 2 2
+85 85 85 85 85 85 85 85
+85 21845 21845 21845 85 21845 21845 21845
+85 21845 1431655765 1431655765 85 21845 1431655765 1431655765
+85 21845 1431655765 6148914691236517205 85 21845 1431655765 6148914691236517205
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+2 2 2 2 2 2 2 2
+85 85 85 85 85 85 85 85
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+2 2 2 2 2 2 2 2
+85 21845 21845 21845 85 21845 21845 21845
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+2 2 2 2 2 2 2 2
+85 21845 1431655765 1431655765 85 21845 1431655765 1431655765
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+2 2 2 2 2 2 2 2
+85 21845 1431655765 6148914691236517205 85 21845 1431655765 6148914691236517205
+-2 254 254 254 254 254 254 254
+-2 254 254 254 254 254 254 254
+2 2 2 2 2 2 2 2
+85 85 85 85 85 85 85 85
+-2 -2 65534 65534 254 65534 65534 65534
+-2 -2 65534 65534 254 65534 65534 65534
+2 2 2 2 2 2 2 2
+85 21845 21845 21845 85 21845 21845 21845
+-2 -2 -2 4294967294 254 65534 4294967294 4294967294
+-2 -2 -2 4294967294 254 65534 4294967294 4294967294
+2 2 2 2 2 2 2 2
+85 21845 1431655765 1431655765 85 21845 1431655765 1431655765
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+-2 -2 -2 -2 254 65534 4294967294 18446744073709551614
+2 2 2 2 2 2 2 2
+85 21845 1431655765 6148914691236517205 85 21845 1431655765 6148914691236517205
+
-- 
2.34.1




More information about the DTrace-devel mailing list