diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2015-06-27 22:51:38 -0400 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2015-06-28 16:15:19 -0400 |
commit | b3498293409c7838d6786f7e8997ff0391135774 (patch) | |
tree | 480b656a9bb8ea63e904ed3527916f928e48d24c /pp.c | |
parent | 054a3baf7ca16fe022e9a5fd56c158300d5c44f5 (diff) | |
download | perl-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.c | 43 |
1 files changed, 35 insertions, 8 deletions
@@ -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; } |