summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2015-06-27 22:51:38 -0400
committerJarkko Hietaniemi <jhi@iki.fi>2015-06-28 16:15:19 -0400
commitb3498293409c7838d6786f7e8997ff0391135774 (patch)
tree480b656a9bb8ea63e904ed3527916f928e48d24c /pp.c
parent054a3baf7ca16fe022e9a5fd56c158300d5c44f5 (diff)
downloadperl-b3498293409c7838d6786f7e8997ff0391135774.tar.gz
Define left/right shift by negative to mean the reverse shift
Coverity CIDs 104765 and 104766 While at it, also define shifting by more than wordsize in bits to be zero, except that undef 'use integer' (use IVs) right overshift for negative shiftees means -1. (This is another corner where C leaves things undefined. A common behavior is "shift by modulo worbits", so that e.g. 1 >> 64 == 1 >> (64 % 64) == 1 >> 0, but this is completely accidental.) (Coverity didn't flag this, harder to detect statically.) Discussion thread at http://www.nntp.perl.org/group/perl.perl5.porters/2015/06/msg228842.html
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c43
1 files changed, 35 insertions, 8 deletions
diff --git a/pp.c b/pp.c
index af2270e131..1e46dd1d20 100644
--- a/pp.c
+++ b/pp.c
@@ -1905,6 +1905,37 @@ PP(pp_subtract)
}
}
+#define IV_BITS (IVSIZE * 8)
+
+static UV S_uv_shift(UV uv, int shift, bool left)
+{
+ if (shift < 0) {
+ shift = -shift;
+ left = !left;
+ }
+ if (shift >= IV_BITS) {
+ return 0;
+ }
+ return left ? uv << shift : uv >> shift;
+}
+
+static IV S_iv_shift(IV iv, int shift, bool left)
+{
+ if (shift < 0) {
+ shift = -shift;
+ left = !left;
+ }
+ if (shift >= IV_BITS) {
+ return iv < 0 ? -1 : 0;
+ }
+ return left ? iv << shift : iv >> shift;
+}
+
+#define UV_LEFT_SHIFT(uv, shift) S_uv_shift(uv, shift, TRUE)
+#define UV_RIGHT_SHIFT(uv, shift) S_uv_shift(uv, shift, FALSE)
+#define IV_LEFT_SHIFT(iv, shift) S_iv_shift(iv, shift, TRUE)
+#define IV_RIGHT_SHIFT(iv, shift) S_iv_shift(iv, shift, FALSE)
+
PP(pp_left_shift)
{
dSP; dATARGET; SV *svl, *svr;
@@ -1914,12 +1945,10 @@ PP(pp_left_shift)
{
const IV shift = SvIV_nomg(svr);
if (PL_op->op_private & HINT_INTEGER) {
- const IV i = SvIV_nomg(svl);
- SETi(i << shift);
+ SETi(IV_LEFT_SHIFT(SvIV_nomg(svl), shift));
}
else {
- const UV u = SvUV_nomg(svl);
- SETu(u << shift);
+ SETu(UV_LEFT_SHIFT(SvUV_nomg(svl), shift));
}
RETURN;
}
@@ -1934,12 +1963,10 @@ PP(pp_right_shift)
{
const IV shift = SvIV_nomg(svr);
if (PL_op->op_private & HINT_INTEGER) {
- const IV i = SvIV_nomg(svl);
- SETi(i >> shift);
+ SETi(IV_RIGHT_SHIFT(SvIV_nomg(svl), shift));
}
else {
- const UV u = SvUV_nomg(svl);
- SETu(u >> shift);
+ SETu(UV_RIGHT_SHIFT(SvUV_nomg(svl), shift));
}
RETURN;
}