ghcjs / ghcjs-base

base library for GHCJS for JavaScript interaction and marshalling, used by higher level libraries like JSC
MIT License
45 stars 67 forks source link

Data.JSString.pack throws RangeError on lists with certain thunk structures #129

Open Dridus opened 4 years ago

Dridus commented 4 years ago

Might be related to https://github.com/ghcjs/ghcjs-base/issues/128

I encountered it in the wild by way of showFFloat (Just 6) (2.2e-2), here's a reproduction case

import Numeric (showFFloat)
import Data.JSString (pack, unpack)

main :: IO ()
main = do
  putStrLn . unpack . pack $ showFFloat (Just 2) 2.2e-2 ""

ghcjs ./test.hs && node test.jsexe/all.js results in:

Haskell main thread: RangeError: Invalid code point: NaN
RangeError: Invalid code point: NaN
    at /home/ross/3rd/reflex-platform/test.jsexe/all.js:20550:29
    at h$jsstringPack (/home/ross/3rd/reflex-platform/test.jsexe/all.js:20711:36)
    at h$$Kt (/home/ross/3rd/reflex-platform/test.jsexe/all.js:57018:11)
    at h$runThreadSlice (/home/ross/3rd/reflex-platform/test.jsexe/all.js:6845:11)
    at h$runThreadSliceCatch (/home/ross/3rd/reflex-platform/test.jsexe/all.js:6814:12)
    at Immediate.h$mainLoop [as _onImmediate] (/home/ross/3rd/reflex-platform/test.jsexe/all.js:6809:9)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)

via node and something similar via Safari.

this is using GHCJS 8.6.0.1 (GHC 8.6.5), as packaged with reflex-platform 58873162d542c14cf198e9711986c046b06a18da

when compiled via GHC with Data.Text (pack, unpack), instead the output is the expected

0.022000
Dridus commented 4 years ago

using Safari devtools, the exception stack is:

pushing on the test case a bit, I found that reproduction is strangely fragile. this doesn't blow up:

{-# OPTIONS_GHC -Wall #-}
import Data.Text (pack, unpack)
import GHC.Float
import GHC.Show (intToDigit)
import System.IO (hFlush, stdout)

test :: String
test = 
  let
    (is, e) = floatToDigits 10 (2.2e-2 :: Double)
    (ei,is') = roundTo 10 6 (replicate (-e) 0 ++ is)
    d:ds' = map intToDigit (if ei > 0 then is' else 0:is')
  in
    d : (if null ds' then "" else '.':ds')

main :: IO ()
main = do
  putStrLn . unpack . pack $ test
  --- hFlush stdout

and I see the correct output (0.022000) but it blows up if I uncomment the flush