Skip to content

Commit

Permalink
[mypyc] Fixes to float to int conversion (#14936)
Browse files Browse the repository at this point in the history
Fix undefined behavior due to converting a negative float to an unsigned
integer type. Fix edge cases on 32-bit platforms.

The first issue was caught by the testI32BasicOps test case, but only in
some configurations, it looks like.
  • Loading branch information
JukkaL authored Mar 22, 2023
1 parent 9944d5f commit aa2679b
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 2 deletions.
4 changes: 2 additions & 2 deletions mypyc/lib-rt/int_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ PyObject *CPyLong_FromStr(PyObject *o) {
}

CPyTagged CPyTagged_FromFloat(double f) {
if (f < (double)CPY_TAGGED_MAX && f > CPY_TAGGED_MIN) {
return (CPyTagged)f << 1;
if (f < ((double)CPY_TAGGED_MAX + 1.0) && f > (CPY_TAGGED_MIN - 1.0)) {
return (Py_ssize_t)f << 1;
}
PyObject *o = PyLong_FromDouble(f);
if (o == NULL)
Expand Down
10 changes: 10 additions & 0 deletions mypyc/test-data/run-floats.test
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ def test_explicit_conversion_to_int() -> None:
else:
assert repr(int(x)) == repr(int_any(x))

# Test some edge cases
assert 2**30 == int(2.0**30 + int())
assert 2**30 - 1 == int(1073741823.9999999 + int()) # math.nextafter(2.0**30, 0))
assert -2**30 - 1 == int(-2.0**30 - 1 + int())
assert -2**30 == int(-1073741824.9999998 + int()) # math.nextafter(-2.0**30 - 1, 0)
assert 2**62 == int(2.0**62 + int())
assert 2**62 == int(2.0**62 - 1 + int())
assert -2**62 == int(-2.0**62 + int())
assert -2**62 == int(-2.0**62 - 1 + int())

def str_to_float(x: str) -> float:
return float(x)

Expand Down
1 change: 1 addition & 0 deletions test-data/unit/lib-stub/math.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ def copysign(__x: float, __y: float) -> float: ...
def isinf(__x: float) -> bool: ...
def isnan(__x: float) -> bool: ...
def isfinite(__x: float) -> bool: ...
def nextafter(__x: float, __y: float) -> float: ...

0 comments on commit aa2679b

Please sign in to comment.