[pypy-commit] pypy default: Bug in the overflow detection code in the timeout argument to various
arigo
pypy.commits at gmail.com
Mon Jul 18 04:28:40 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r85748:47e0578e9553
Date: 2016-07-18 10:29 +0200
http://bitbucket.org/pypy/pypy/changeset/47e0578e9553/
Log: Bug in the overflow detection code in the timeout argument to
various thread/threading primitives. The cast from float to 64-bit
integer needs to be done carefully, because floats don't have 64
bits of precision.
diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py
--- a/pypy/module/thread/os_lock.py
+++ b/pypy/module/thread/os_lock.py
@@ -9,12 +9,9 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.error import oefmt
-from rpython.rlib.rarithmetic import r_longlong
+from rpython.rlib.rarithmetic import r_longlong, ovfcheck_float_to_longlong
-LONGLONG_MAX = r_longlong(2 ** (r_longlong.BITS-1) - 1)
-TIMEOUT_MAX = LONGLONG_MAX
-
RPY_LOCK_FAILURE, RPY_LOCK_ACQUIRED, RPY_LOCK_INTR = range(3)
def parse_acquire_args(space, blocking, timeout):
@@ -29,10 +26,12 @@
elif timeout == -1.0:
microseconds = -1
else:
- timeout *= 1e6
- if timeout > float(TIMEOUT_MAX):
+ # 0.0 => 0.0, but otherwise tends to round up
+ timeout = timeout * 1e6 + 0.999
+ try:
+ microseconds = ovfcheck_float_to_longlong(timeout)
+ except OverflowError:
raise oefmt(space.w_OverflowError, "timeout value is too large")
- microseconds = r_longlong(timeout)
return microseconds
@@ -45,7 +44,8 @@
# Run signal handlers if we were interrupted
space.getexecutioncontext().checksignals()
if microseconds >= 0:
- microseconds = r_longlong(endtime - (time.time() * 1e6))
+ microseconds = r_longlong((endtime - (time.time() * 1e6))
+ + 0.999)
# Check for negative values, since those mean block
# forever
if microseconds <= 0:
diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py
--- a/pypy/module/thread/test/test_lock.py
+++ b/pypy/module/thread/test/test_lock.py
@@ -64,6 +64,25 @@
else:
assert self.runappdirect, "missing lock._py3k_acquire()"
+ def test_py3k_acquire_timeout_overflow(self):
+ import thread
+ lock = thread.allocate_lock()
+ if not hasattr(lock, '_py3k_acquire'):
+ skip("missing lock._py3k_acquire()")
+ maxint = 2**63 - 1
+ boundary = int(maxint * 1e-6)
+ for i in [-100000, -10000, -1000, -100, -10, -1, 0,
+ 1, 10, 100, 1000, 10000, 100000]:
+ timeout = (maxint + i) * 1e-6
+ try:
+ lock._py3k_acquire(True, timeout=timeout)
+ except OverflowError:
+ got_ovf = True
+ else:
+ got_ovf = False
+ lock.release()
+ assert (i, got_ovf) == (i, int(timeout * 1e6 + 0.999) > maxint)
+
@py.test.mark.xfail(machine()=='s390x', reason='may fail under heavy load')
def test_ping_pong(self):
# The purpose of this test is that doing a large number of ping-pongs
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -14,6 +14,8 @@
integer operation did overflow
ovfcheck_float_to_int
convert to an integer or raise OverflowError
+ovfcheck_float_to_longlong
+ convert to a longlong or raise OverflowError
r_longlong
like r_int but double word size
r_ulonglong
@@ -182,6 +184,18 @@
# int(float(i)) != i because of rounding issues.
# These are the minimum and maximum float value that can
# successfully be casted to an int.
+
+# The following values are not quite +/-sys.maxint.
+# Note the "<= x <" here, as opposed to "< x <" above.
+# This is justified by test_typed in translator/c/test.
+def ovfcheck_float_to_longlong(x):
+ from rpython.rlib.rfloat import isnan
+ if isnan(x):
+ raise OverflowError
+ if -9223372036854776832.0 <= x < 9223372036854775296.0:
+ return r_longlong(x)
+ raise OverflowError
+
if sys.maxint == 2147483647:
def ovfcheck_float_to_int(x):
from rpython.rlib.rfloat import isnan
@@ -191,16 +205,8 @@
return int(x)
raise OverflowError
else:
- # The following values are not quite +/-sys.maxint.
- # Note the "<= x <" here, as opposed to "< x <" above.
- # This is justified by test_typed in translator/c/test.
def ovfcheck_float_to_int(x):
- from rpython.rlib.rfloat import isnan
- if isnan(x):
- raise OverflowError
- if -9223372036854776832.0 <= x < 9223372036854775296.0:
- return int(x)
- raise OverflowError
+ return int(ovfcheck_float_to_longlong(x))
def compute_restype(self_type, other_type):
if self_type is other_type:
More information about the pypy-commit
mailing list