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
aecd25eea9
commit
d5b14891eb
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=270029
@ -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