76 lines
2.1 KiB
Diff
76 lines
2.1 KiB
Diff
From 7e5b390a008ccad094a39c350f385d58e8a5102a Mon Sep 17 00:00:00 2001
|
|
From: Karl Williamson <khw@cpan.org>
|
|
Date: Fri, 3 May 2019 13:57:47 -0600
|
|
Subject: [PATCH] Remove undefined behavior from IV shifting
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
It is undefined behavior to shift a negative integer to the left. This
|
|
commit avoids that by treating the value as unsigned, then casting back
|
|
to integer for return.
|
|
|
|
Petr Písař: Ported to 5.30.0 from
|
|
814735a391b874af8f00eaf89469e5ec7f38cd4aa.
|
|
|
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
|
---
|
|
asan_ignore | 5 -----
|
|
pp.c | 21 ++++++++++++++++++++-
|
|
2 files changed, 20 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/asan_ignore b/asan_ignore
|
|
index e0f5685..f520546 100644
|
|
--- a/asan_ignore
|
|
+++ b/asan_ignore
|
|
@@ -18,11 +18,6 @@
|
|
|
|
fun:Perl_pp_i_*
|
|
|
|
-# Perl's << is defined as using the underlying C's << operator, with the
|
|
-# same undefined behaviour for shifts greater than the word size.
|
|
-# (UVs normally, IVs with 'use integer')
|
|
-
|
|
-fun:Perl_pp_left_shift
|
|
|
|
# this function numifies the field width in eg printf "%10f".
|
|
# It has its own overflow detection, so don't warn about it
|
|
diff --git a/pp.c b/pp.c
|
|
index 7afb090..3ca04e1 100644
|
|
--- a/pp.c
|
|
+++ b/pp.c
|
|
@@ -1991,10 +1991,29 @@ static IV S_iv_shift(IV iv, int shift, bool left)
|
|
shift = -shift;
|
|
left = !left;
|
|
}
|
|
+
|
|
if (UNLIKELY(shift >= IV_BITS)) {
|
|
return iv < 0 && !left ? -1 : 0;
|
|
}
|
|
- return left ? iv << shift : iv >> shift;
|
|
+ /* For left shifts, perl 5 has chosen to treat the value as unsigned for
|
|
+ * the * purposes of shifting, then cast back to signed. This is very
|
|
+ * different from perl 6:
|
|
+ *
|
|
+ * $ perl6 -e 'say -2 +< 5'
|
|
+ * -64
|
|
+ *
|
|
+ * $ ./perl -le 'print -2 << 5'
|
|
+ * 18446744073709551552
|
|
+ * */
|
|
+ if (left) {
|
|
+ if (iv == IV_MIN) { /* Casting this to a UV is undefined behavior */
|
|
+ return 0;
|
|
+ }
|
|
+ return (IV) (((UV) iv) << shift);
|
|
+ }
|
|
+
|
|
+ /* Here is right shift */
|
|
+ return iv >> shift;
|
|
}
|
|
|
|
#define UV_LEFT_SHIFT(uv, shift) S_uv_shift(uv, shift, TRUE)
|
|
--
|
|
2.20.1
|
|
|