From: stassats <stassats@us...>  20120831 21:39:32

The branch "master" has been updated in SBCL: via b8359d1e6db950b0a7bd4a255ed6d57a3eac08ef (commit) from 34d75fd54651830d53ebd41ddebaf6ac1c76ba62 (commit)  Log  commit b8359d1e6db950b0a7bd4a255ed6d57a3eac08ef Author: Stas Boukarev <stassats@...> Date: Sat Sep 1 01:38:13 2012 +0400 Reading floats with large exponents no longer takes too much time. Reading 1.0s1000000000000000 will attempt to construct a very large bignum, which takes a considerable amount of time just to report in the end that it cannot be represented as a float. Truncate the exponent to manageable size before raising it. Fixes lp#309070. Thanks to Paul Khuong for the help.  NEWS  2 ++ src/code/reader.lisp  22 +++++++++++++++++++++ tests/reader.pure.lisp  5 +++++ 3 files changed, 28 insertions(+), 1 deletions() diff git a/NEWS b/NEWS index 647df01..47be00e 100644  a/NEWS +++ b/NEWS @@ 4,6 +4,8 @@ changes relative to sbcl1.0.58: source annotation of DISASSEMBLE output. Defaults to T. * optimization: CL:SORT and CL:STABLESORT of lists are faster and use fewer comparisons, particularly on almostsorted inputs. + * bug fix: Reading floats with large exponents no longer takes too much time + before reporting that the exponent is too large. * documentation: a section on random number generation has been added to the manual. (lp#656839) diff git a/src/code/reader.lisp b/src/code/reader.lisp index 5d85c73..08a5286 100644  a/src/code/reader.lisp +++ b/src/code/reader.lisp @@ 1409,6 +1409,24 @@ extended <packagename>::<forminpackage> syntax." (the index (* num base)))))))) (setq number (+ num (* number basepower))))))) +(defun truncateexponent (exponent number divisor) + "Truncate exponent if it's too large for a float" + ;; Work with base2 logarithms to avoid conversions to floats, + ;; and convert to base10 conservatively at the end. + ;; Use the least positive float, because denormalized exponent + ;; can be larger than normalized. + (let* ((maxexponent ( (nthvalue + 1 + (decodefloat leastpositivelongfloat)))) + (numbermagnitude (integerlength number)) + (divisormagnitude (1 (integerlength divisor))) + (magnitude ( numbermagnitude divisormagnitude))) + (if (minusp exponent) + (max exponent (ceiling ( (+ maxexponent magnitude)) + (floor (log 10 2)))) + (min exponent (floor ( maxexponent magnitude) + (floor (log 10 2))))))) + (defun makefloat (stream) ;; Assume that the contents of *readbuffer* are a legal float, with nothing ;; else after it. @@ 1469,6 +1487,7 @@ extended <packagename>::<forminpackage> syntax." (#\F 'singlefloat) (#\D 'doublefloat) (#\L 'longfloat))) + (exponent (truncateexponent exponent number divisor)) (result (makefloataux (* (expt 10 exponent) number) divisor floatformat stream))) (returnfrom makefloat @@ 1481,7 +1500,8 @@ extended <packagename>::<forminpackage> syntax." (typeerror (c) (error 'readerimpossiblenumbererror :error c :stream stream  :formatcontrol "failed to build float")))) + :formatcontrol "failed to build float from ~a" + :formatarguments (list (readbuffertostring)))))) (defun makeratio (stream) ;; Assume *READBUFFER* contains a legal ratio. Build the number from diff git a/tests/reader.pure.lisp b/tests/reader.pure.lisp index 7d29b18..04d9dda 100644  a/tests/reader.pure.lisp +++ b/tests/reader.pure.lisp @@ 283,3 +283,8 @@ (readfromstring "cl::'foo") (packagelockviolation () :violated!))))) + +(withtest (:name :bug309070) + (withtimeout 10 + (assert (raiseserror? (readfromstring "10e10000000000000000000") + sbkernel:readerimpossiblenumbererror))))  hooks/postreceive  SBCL 