Skip to content

Commit

Permalink
Fix typecast
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
kvanhees committed Aug 4, 2022
1 parent 7e9ce1e commit 9f99312
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 28 deletions.
48 changes: 28 additions & 20 deletions libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -2513,33 +2513,16 @@ static void
dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
dt_irlist_t *dlp, dt_regset_t *drp)
{
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)) {
int mst;
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)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
Expand All @@ -2550,6 +2533,31 @@ 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;
size_t srcsize = dt_node_type_size(src);
size_t dstsize = dt_node_type_size(dst);
int n = (sizeof(uint64_t) - dstsize) * NBBY;
int cast = 1;

if (dst->dn_reg != src->dn_reg)
emit(dlp, BPF_MOV_REG(dst->dn_reg, src->dn_reg));

if (n == 0) {
cast = 0;
} else if (dstsize > srcsize) {
if (dstsigned || !srcsigned)
cast = 0;
} else if (dstsize == srcsize) {
if (dstsigned == srcsigned)
cast = 0;
}

if (cast) {
emit(dlp, BPF_ALU64_IMM(BPF_LSH, dst->dn_reg, n));
emit(dlp, BPF_ALU64_IMM(dstsigned ? BPF_ARSH : BPF_RSH, dst->dn_reg, n));
}
}
}

Expand Down
25 changes: 17 additions & 8 deletions libdtrace/dt_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2123,18 +2123,27 @@ 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;
int n = (sizeof(uint64_t) - dstsize) * NBBY;
int cast = 1;

if (n == 0) {
cast = 0;
} else if (dstsize > srcsize) {
if (dstsigned || !srcsigned)
cast = 0;
} else if (dstsize == srcsize) {
if (dstsigned == srcsigned)
cast = 0;
}

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 (cast) {
rp->dn_value <<= n;
if (lp->dn_flags & DT_NF_SIGNED)
if (dstsigned)
rp->dn_value = (intmax_t)rp->dn_value >> n;
else
rp->dn_value = rp->dn_value >> n;
rp->dn_value >>= n;
}

dt_node_type_propagate(lp, rp);
Expand Down
157 changes: 157 additions & 0 deletions test/unittest/arithmetic/tst.cast-exp.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* 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)
* The .r results file can be generated by copying this file
* to a .c file and compiling the resulting C program.
*
* SECTION: Types, Operators, and Expressions/Arithmetic Operators
*/
/* @@runtest-opts: -qC -DUSE_AS_D_SCRIPT */

#ifndef USE_AS_D_SCRIPT
#include <stdio.h>
#endif

signed char c, c0;
short s, s0;
int i, i0;
long long l, l0;
unsigned char C, C0;
unsigned short S, S0;
unsigned int I, I0;
unsigned long long L, L0;

#ifdef USE_AS_D_SCRIPT
#define FMT "%d %d %d %d %d %d %d %d\n"
#else
#define FMT "%hhd %hd %d %lld %hhu %hu %u %llu\n"
#endif

#define TEST(x) \
c = (signed 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(FMT, c, s, i, l, C, S, I, L)

#ifdef USE_AS_D_SCRIPT
BEGIN
#else
int main(int c_unused, char **v_unused)
#endif
{
/* from scalar */
TEST(-2);
TEST(0xfffffffffffffffe);
TEST(0xfffffffe);
TEST(0xfffe);
TEST(0xfe);
TEST(2);
TEST(0x55);
TEST(0x5555);
TEST(0x55555555);
TEST(0x5555555555555555);

/* from signed char */
c0 = -2; TEST(c0);
c0 = 0xfe; TEST(c0);
c0 = 2; TEST(c0);
c0 = 0x55; TEST(c0);

/* from short */
s0 = -2; TEST(s0);
s0 = 0xfffe; TEST(s0);
s0 = 2; TEST(s0);
s0 = 0x5555; TEST(s0);

/* from int */
i0 = -2; TEST(i0);
i0 = 0xfffffffe; TEST(i0);
i0 = 2; TEST(i0);
i0 = 0x55555555; TEST(i0);

/* from long long */
l0 = -2; TEST(l0);
l0 = 0xfffffffffffffffe; TEST(l0);
l0 = 2; TEST(l0);
l0 = 0x5555555555555555; TEST(l0);

/* from unsigned char */
C0 = -2; TEST(C0);
C0 = 0xfe; TEST(C0);
C0 = 2; TEST(C0);
C0 = 0x55; TEST(C0);

/* from unsigned short */
S0 = -2; TEST(S0);
S0 = 0xfffe; TEST(S0);
S0 = 2; TEST(S0);
S0 = 0x5555; TEST(S0);

/* from unsigned int */
I0 = -2; TEST(I0);
I0 = 0xfffffffe; TEST(I0);
I0 = 2; TEST(I0);
I0 = 0x55555555; TEST(I0);

/* from unsigned long long */
L0 = -2; TEST(L0);
L0 = 0xfffffffffffffffe; TEST(L0);
L0 = 2; TEST(L0);
L0 = 0x5555555555555555; TEST(L0);

/* from other constant expressions */
TEST((signed char)(-1));
TEST((short)(-1));
TEST((int)(-1));
TEST((long long)(-1));
TEST((unsigned char)(-1));
TEST((unsigned short)(-1));
TEST((unsigned int)(-1));
TEST((unsigned long long)(-1));

TEST((long long)(signed char)(-1));
TEST((long long)(short)(-1));
TEST((long long)(int)(-1));
TEST((long long)(long long)(-1));
TEST((long long)(unsigned char)(-1));
TEST((long long)(unsigned short)(-1));
TEST((long long)(unsigned int)(-1));
TEST((long long)(unsigned long long)(-1));

/* from other expressions */
l0 = -1;
TEST((signed char)l0);
TEST((short)l0);
TEST((int)l0);
TEST((long long)l0);
TEST((unsigned char)l0);
TEST((unsigned short)l0);
TEST((unsigned int)l0);
TEST((unsigned long long)l0);

TEST((long long)(signed char)l0);
TEST((long long)(short)l0);
TEST((long long)(int)l0);
TEST((long long)(long long)l0);
TEST((long long)(unsigned char)l0);
TEST((long long)(unsigned short)l0);
TEST((long long)(unsigned int)l0);
TEST((long long)(unsigned long long)l0);

#ifdef USE_AS_D_SCRIPT
exit (0);
#else
return 0;
#endif
}
75 changes: 75 additions & 0 deletions test/unittest/arithmetic/tst.cast-exp.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
-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
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 255 255 255 255 255 255 255
-1 -1 65535 65535 255 65535 65535 65535
-1 -1 -1 4294967295 255 65535 4294967295 4294967295
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 255 255 255 255 255 255 255
-1 -1 65535 65535 255 65535 65535 65535
-1 -1 -1 4294967295 255 65535 4294967295 4294967295
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 255 255 255 255 255 255 255
-1 -1 65535 65535 255 65535 65535 65535
-1 -1 -1 4294967295 255 65535 4294967295 4294967295
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615
-1 255 255 255 255 255 255 255
-1 -1 65535 65535 255 65535 65535 65535
-1 -1 -1 4294967295 255 65535 4294967295 4294967295
-1 -1 -1 -1 255 65535 4294967295 18446744073709551615

0 comments on commit 9f99312

Please sign in to comment.