Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Avoid undefined behaviour when overshifting
Shifting by a negative amount or more than the width of the value is
undefined behaviour in C.  Adopt the semantics from Perl 5:

 - Negative shift inverts the direction
 - Left overshift yields zero
 - Right overshift yields zero for positive numbers,
   -1 for negative numbers
  • Loading branch information
ilmari committed Dec 2, 2015
1 parent 6e4b90f commit 7b35375
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 2 deletions.
1 change: 1 addition & 0 deletions build/Makefile.in
Expand Up @@ -80,6 +80,7 @@ OBJECTS = src/core/callsite@obj@ \
src/core/ops@obj@ \
src/core/hll@obj@ \
src/core/loadbytecode@obj@ \
src/math/int@obj@ \
src/math/num@obj@ \
src/core/coerce@obj@ \
src/core/dll@obj@ \
Expand Down
4 changes: 2 additions & 2 deletions src/core/interp.c
Expand Up @@ -745,11 +745,11 @@ void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContex
cur_op += 4;
goto NEXT;
OP(blshift_i):
GET_REG(cur_op, 0).i64 = GET_REG(cur_op, 2).i64 << GET_REG(cur_op, 4).i64;
GET_REG(cur_op, 0).i64 = MVM_int_shl(tc, GET_REG(cur_op, 2).i64, GET_REG(cur_op, 4).i64);
cur_op += 6;
goto NEXT;
OP(brshift_i):
GET_REG(cur_op, 0).i64 = GET_REG(cur_op, 2).i64 >> GET_REG(cur_op, 4).i64;
GET_REG(cur_op, 0).i64 = MVM_int_shr(tc, GET_REG(cur_op, 2).i64, GET_REG(cur_op, 4).i64);
cur_op += 6;
goto NEXT;
OP(pow_i): {
Expand Down
21 changes: 21 additions & 0 deletions src/math/int.c
@@ -0,0 +1,21 @@
#include "moar.h"

/* copied from perl5/pp.c:S_iv_shift */
static MVMint64 S_int_shift(MVMint64 value, MVMint64 shift, MVMint64 left) {
if (shift < 0) {
shift = -shift;
left = !left;
}
if (shift >= sizeof(MVMint64) * CHAR_BIT) {
return value < 0 && !left ? -1 : 0;
}
return left ? value << shift : value >> shift;
}

MVMint64 MVM_int_shl(MVMThreadContext *tc, MVMint64 value, MVMint64 shift) {
return S_int_shift(value, shift, 1);
}

MVMint64 MVM_int_shr(MVMThreadContext *tc, MVMint64 value, MVMint64 shift) {
return S_int_shift(value, shift, 0);
}
2 changes: 2 additions & 0 deletions src/math/int.h
@@ -0,0 +1,2 @@
MVMint64 MVM_int_shl(MVMThreadContext *tc, MVMint64 value, MVMint64 shift);
MVMint64 MVM_int_shr(MVMThreadContext *tc, MVMint64 value, MVMint64 shift);
1 change: 1 addition & 0 deletions src/moar.h
Expand Up @@ -105,6 +105,7 @@ MVM_PUBLIC const MVMint32 MVM_jit_support(void);
#include "core/threads.h"
#include "core/hll.h"
#include "core/loadbytecode.h"
#include "math/int.h"
#include "math/num.h"
#include "core/coerce.h"
#include "core/ext.h"
Expand Down

0 comments on commit 7b35375

Please sign in to comment.