[pypy-commit] pypy refactor-PyFloat_FromString: refactor possible recursion in PyFloat_FromString

mattip pypy.commits at gmail.com
Thu Nov 16 10:21:27 EST 2017


Author: Matti Picus <matti.picus at gmail.com>
Branch: refactor-PyFloat_FromString
Changeset: r93055:57019e77c377
Date: 2017-11-16 17:19 +0200
http://bitbucket.org/pypy/pypy/changeset/57019e77c377/

Log:	refactor possible recursion in PyFloat_FromString

diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -1,12 +1,12 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib import rarithmetic
 from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
     cpython_struct,
     CANNOT_FAIL, cpython_api, PyObject, build_type_checkers, CONST_STRING)
 from pypy.module.cpyext.pyobject import (
     make_typedescr, track_reference, from_ref)
-from pypy.interpreter.error import OperationError
 from rpython.rlib.rstruct import runpack
-from pypy.objspace.std.floatobject import W_FloatObject
+from pypy.objspace.std.floatobject import W_FloatObject, basestring_to_float
 
 PyFloatObjectStruct = lltype.ForwardReference()
 PyFloatObject = lltype.Ptr(PyFloatObjectStruct)
@@ -66,7 +66,10 @@
     """Create a PyFloatObject object based on the string value in str, or
     NULL on failure.  The pend argument is ignored.  It remains only for
     backward compatibility."""
-    return space.call_function(space.w_float, w_obj)
+    # avoid space.call_function(space.w_float, w_obj) since PyFloat_FromString
+    # could be type.tp_as_number.nb_float which would recurse
+    value = basestring_to_float(space, w_obj)
+    return space.newfloat(value)
 
 @cpython_api([CONST_STRING, rffi.INT_real], rffi.DOUBLE, error=-1.0)
 def _PyFloat_Unpack4(space, ptr, le):
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -135,6 +135,28 @@
         return space.w_NotImplemented
     return func_with_new_name(_compare, 'descr_' + opname)
 
+def basestring_to_float(space, w_value):
+    def _string_to_float(space, w_source, string):
+        try:
+            return rfloat.string_to_float(string)
+        except ParseStringError as e:
+            raise wrap_parsestringerror(space, e, w_source)
+
+    if space.isinstance_w(w_value, space.w_unicode):
+        from unicodeobject import unicode_to_decimal_w
+        value = _string_to_float(space, w_value,
+                     unicode_to_decimal_w(space, w_value))
+    else:
+        try:
+            value = space.charbuf_w(w_value)
+        except OperationError as e:
+            if e.match(space, space.w_TypeError):
+                raise oefmt(
+                space.w_TypeError,
+                "float() argument must be a string or a number")
+            raise
+        value = _string_to_float(space, w_value, value)
+    return value
 
 class W_FloatObject(W_Root):
     """This is a implementation of the app-level 'float' type.
@@ -193,32 +215,14 @@
     @staticmethod
     @unwrap_spec(w_x=WrappedDefault(0.0))
     def descr__new__(space, w_floattype, w_x):
-        def _string_to_float(space, w_source, string):
-            try:
-                return rfloat.string_to_float(string)
-            except ParseStringError as e:
-                raise wrap_parsestringerror(space, e, w_source)
-
         w_value = w_x     # 'x' is the keyword argument name in CPython
         if space.lookup(w_value, "__float__") is not None:
             w_obj = space.float(w_value)
             if space.is_w(w_floattype, space.w_float):
                 return w_obj
             value = space.float_w(w_obj)
-        elif space.isinstance_w(w_value, space.w_unicode):
-            from unicodeobject import unicode_to_decimal_w
-            value = _string_to_float(space, w_value,
-                                     unicode_to_decimal_w(space, w_value))
         else:
-            try:
-                value = space.charbuf_w(w_value)
-            except OperationError as e:
-                if e.match(space, space.w_TypeError):
-                    raise oefmt(
-                        space.w_TypeError,
-                        "float() argument must be a string or a number")
-                raise
-            value = _string_to_float(space, w_value, value)
+            value = basestring_to_float(space, w_value)
         w_obj = space.allocate_instance(W_FloatObject, w_floattype)
         W_FloatObject.__init__(w_obj, value)
         return w_obj


More information about the pypy-commit mailing list