py: Fix bug with right-shifting small ints by large amounts.

Undefined behavior in C, needs explicit check.
This commit is contained in:
Paul Sokolovsky 2014-11-02 02:39:41 +02:00
parent a58713a899
commit 039887a0ac
3 changed files with 24 additions and 0 deletions

View File

@ -233,6 +233,11 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
}
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
// int >> int
if (arg1 >= BITS_PER_WORD) {
// Shifting to big amounts is underfined behavior
// in C and is CPU-dependent; propagate sign bit.
arg1 = BITS_PER_WORD - 1;
}
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
} else {
// shouldn't happen

View File

@ -337,6 +337,11 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
} else {
// standard precision is enough for right-shift
if (rhs_val >= BITS_PER_WORD) {
// Shifting to big amounts is underfined behavior
// in C and is CPU-dependent; propagate sign bit.
rhs_val = BITS_PER_WORD - 1;
}
lhs_val >>= rhs_val;
}
break;

View File

@ -48,3 +48,17 @@ a -= 1
print(a)
# This would overflow
#a -= 1
# Shifts to big amounts are undefined behavior in C and is CPU-specific
# These are compile-time constexprs
print(1 >> 32)
print(1 >> 64)
print(1 >> 128)
# These are runtime calcs
a = 1
print(a >> 32)
print(a >> 64)
print(a >> 128)