sh: Mask off shift distance (<< and >>) in arithmetic.
In C, shift distances equal to or larger than the number of bits in the operand result in undefined behaviour. As part of eliminating undefined behaviour in arithmetic, mask off the distance like Java and JavaScript specify and C on x86 usually does. Assumption: conversion from unsigned to signed retains the two's complement bits. Assumption: uintmax_t has no padding bits.
This commit is contained in:
parent
82e14020fd
commit
948728c4a6
@ -139,9 +139,10 @@ static arith_t do_binop(int op, arith_t a, arith_t b)
|
||||
case ARITH_SUB:
|
||||
return (uintmax_t)a - (uintmax_t)b;
|
||||
case ARITH_LSHIFT:
|
||||
return (uintmax_t)a << b;
|
||||
return (uintmax_t)a <<
|
||||
((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1));
|
||||
case ARITH_RSHIFT:
|
||||
return a >> b;
|
||||
return a >> ((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1));
|
||||
case ARITH_LT:
|
||||
return a < b;
|
||||
case ARITH_LE:
|
||||
|
@ -20,6 +20,7 @@ FILES+= arith10.0
|
||||
FILES+= arith11.0
|
||||
FILES+= arith12.0
|
||||
FILES+= arith13.0
|
||||
FILES+= arith14.0
|
||||
FILES+= assign1.0
|
||||
FILES+= cmdsubst1.0
|
||||
FILES+= cmdsubst2.0
|
||||
|
40
bin/sh/tests/expansion/arith14.0
Normal file
40
bin/sh/tests/expansion/arith14.0
Normal file
@ -0,0 +1,40 @@
|
||||
# $FreeBSD$
|
||||
# Check that <</>> use the low bits of the shift count.
|
||||
|
||||
if [ $((1<<16<<16)) = 0 ]; then
|
||||
width=32
|
||||
elif [ $((1<<32<<32)) = 0 ]; then
|
||||
width=64
|
||||
elif [ $((1<<64<<64)) = 0 ]; then
|
||||
width=128
|
||||
elif [ $((1<<64>>64)) = 1 ]; then
|
||||
# Integers are wider than 128 bits; assume arbitrary precision.
|
||||
# Nothing to test here.
|
||||
exit 0
|
||||
else
|
||||
echo "Cannot determine integer width"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
twowidth=$((width * 2))
|
||||
j=43 k=$((1 << (width - 2))) r=0
|
||||
|
||||
i=0
|
||||
while [ $i -lt $twowidth ]; do
|
||||
if [ "$((j << i))" != "$((j << (i + width)))" ]; then
|
||||
echo "Problem with $j << $i"
|
||||
r=2
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
i=0
|
||||
while [ $i -lt $twowidth ]; do
|
||||
if [ "$((k >> i))" != "$((k >> (i + width)))" ]; then
|
||||
echo "Problem with $k >> $i"
|
||||
r=2
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
exit $r
|
Loading…
Reference in New Issue
Block a user