summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorTAKAI Kousuke <62541129+t-a-k@users.noreply.github.com>2021-04-05 23:59:14 +0900
committerKarl Williamson <khw@cpan.org>2021-04-16 17:16:24 -0600
commit640be82afb9c53a7c1c14d80eee36b6081304db0 (patch)
treec458b5b69d184c77e86fd0cccb746bc423dd358e /t
parent50352f1687ab2f02685a380668c889111cdeeee9 (diff)
downloadperl-640be82afb9c53a7c1c14d80eee36b6081304db0.tar.gz
pp.c: Clip shift amount of <<, >> to avoid overflow
Previously the right operand of bitwise shift operators (shift amount) was implicitly cast from IV to int, but it might lead wrong results if IV does not fit in int. And also, shifting INT_MIN bits used to yield the shiftee unchanged (treated as 0-bit shift instead of negative shift).
Diffstat (limited to 't')
-rw-r--r--t/op/bop.t19
1 files changed, 18 insertions, 1 deletions
diff --git a/t/op/bop.t b/t/op/bop.t
index 31b6531a03..a84992e391 100644
--- a/t/op/bop.t
+++ b/t/op/bop.t
@@ -18,7 +18,7 @@ BEGIN {
# If you find tests are failing, please try adding names to tests to track
# down where the failure is, and supply your new names as a patch.
# (Just-in-time test naming)
-plan tests => 503;
+plan tests => 510;
# numerics
ok ((0xdead & 0xbeef) == 0x9ead);
@@ -40,6 +40,23 @@ ok ((~0 > 0 && do { use integer; ~0 } == -1));
is($shifted, $iv_min, "IV_MIN << 0 yields IV_MIN under 'use integer'");
}
+# GH #18691
+# Exercise some corner cases on shifting more bits than the size of IV/UV.
+# All these should work even if the shift amount doesn't fit in IV or UV.
+is(4 << 2147483648, 0, "4 << 2147483648 yields 0");
+is(16 << 4294967295, 0, "16 << 4294967295 yields 0");
+is(8 >> 4294967296, 0, "8 >> 4294967296 yields 0");
+is(11 << 18446744073709551615, 0, "11 << 18446744073709551615 yields 0");
+is(do { use integer; -9 >> 18446744073709551616 }, -1,
+ "-9 >> 18446744073709551616 under 'use integer' yields -1");
+is(do { use integer; -4 << -2147483648 }, -1,
+ "-4 << -2147483648 under 'use integer' yields -1");
+# Quotes around -9223372036854775808 below are to make it a single term.
+# Without quotes, it will be parsed as an expression with an unary minus
+# operator which will clip the result to IV range under "use integer".
+is(do { use integer; -5 >> '-9223372036854775808' }, 0,
+ "-5 >> -9223372036854775808 under 'use integer' yields 0");
+
my $bits = 0;
for (my $i = ~0; $i; $i >>= 1) { ++$bits; }
my $cusp = 1 << ($bits - 1);