diff options
author | David Mitchell <davem@iabyn.com> | 2014-12-20 16:40:52 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2014-12-31 11:28:51 +0000 |
commit | 53e2bfb7c6a2e8a3171dabe7dbdc24eba77e4bf0 (patch) | |
tree | 0581d4da5f1bccbd72d0632eaa006e972800445d /pp_hot.c | |
parent | 382a7a77501a1e25895d78eca9cb6838c6d7e6a3 (diff) | |
download | perl-53e2bfb7c6a2e8a3171dabe7dbdc24eba77e4bf0.tar.gz |
fix -IV_MIN negations
Doing uv = -iv is undefined behaviour if iv happens to be IV_MIN.
This occurs in several places in the perl sources.
Found by -fsanitize=undefined.
Here's a typical message:
sv.c:2864:7: runtime error: negation of -9223372036854775808 cannot be represented in type 'IV' (aka 'long'); cast to an unsigned type to negate this value to itself
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 9 |
1 files changed, 5 insertions, 4 deletions
@@ -647,8 +647,8 @@ PP(pp_add) if (aiv >= 0) { auv = aiv; auvok = 1; /* Now acting as a sign flag. */ - } else { /* 2s complement assumption for IV_MIN */ - auv = (UV)-aiv; + } else { + auv = (aiv == IV_MIN) ? (UV)aiv : (UV)(-aiv); } } a_valid = 1; @@ -668,7 +668,7 @@ PP(pp_add) buv = biv; buvok = 1; } else - buv = (UV)-biv; + buv = (biv == IV_MIN) ? (UV)biv : (UV)(-biv); } /* ?uvok if value is >= 0. basically, flagged as UV if it's +ve, else "IV" now, independent of how it came in. @@ -709,7 +709,8 @@ PP(pp_add) else { /* Negate result */ if (result <= (UV)IV_MIN) - SETi( -(IV)result ); + SETi(result == (UV)IV_MIN + ? IV_MIN : -(IV)result); else { /* result valid, but out of range for IV. */ SETn( -(NV)result ); |