@@ -178,18 +178,44 @@ parseRealFloat _ Null = pure (0/0)
178178parseRealFloat expected v = typeMismatch expected v
179179{-# INLINE parseRealFloat #-}
180180
181+parseIntegralFromScientific :: forall a. Integral a => String -> Scientific -> Parser a
182+parseIntegralFromScientific expected s =
183+ case Scientific.floatingOrInteger s :: Either Double a of
184+ Right x -> pure x
185+ Left _ -> fail $ "Floating number specified for " ++ expected ++ ": " ++ show s
186+{-# INLINE parseIntegralFromScientific #-}
187+
181188parseIntegral :: Integral a => String -> Value -> Parser a
182−parseIntegral expected = withScientific expected $ pure . truncate
189+parseIntegral expected =
190+ withScientific expected $ parseIntegralFromScientific expected
183191{-# INLINE parseIntegral #-}
184192
193+parseBoundedIntegralFromScientific :: (Bounded a, Integral a) => String -> Scientific -> Parser a
194+parseBoundedIntegralFromScientific expected s = maybe
195+ (fail $ expected ++ " is either floating or will cause over or underflow: " ++ show s)
196+ pure
197+ (Scientific.toBoundedInteger s)
198+{-# INLINE parseBoundedIntegralFromScientific #-}
199+
200+parseBoundedIntegral :: (Bounded a, Integral a) => String -> Value -> Parser a
201+parseBoundedIntegral expected =
202+ withScientific expected $ parseBoundedIntegralFromScientific expected
203+{-# INLINE parseBoundedIntegral #-}
204+
185205parseScientificText :: Text -> Parser Scientific
186206parseScientificText
187207 = either fail pure
188208 . A.parseOnly (A.scientific <* A.endOfInput)
189209 . T.encodeUtf8
190210
191−parseIntegralText :: Integral a => Text -> Parser a
192−parseIntegralText t = truncate <$> parseScientificText t
211+parseIntegralText :: Integral a => String -> Text -> Parser a
212+parseIntegralText expected t =
213+ parseScientificText t >>= parseIntegralFromScientific expected
214+{-# INLINE parseIntegralText #-}
215+
216+parseBoundedIntegralText :: (Bounded a, Integral a) => String -> Text -> Parser a
217+parseBoundedIntegralText expected t =
218+ parseScientificText t >>= parseBoundedIntegralFromScientific expected
193219
194220parseOptionalFieldWith :: (Value -> Parser (Maybe a))
195221 -> Object -> Text -> Parser (Maybe a)
@@ -1115,22 +1141,22 @@ instance HasResolution a => FromJSON (Fixed a) where
11151141 {-# INLINE parseJSON #-}
11161142
11171143instance FromJSON Int where
1118− parseJSON = parseIntegral "Int"
1144+ parseJSON = parseBoundedIntegral "Int"
11191145 {-# INLINE parseJSON #-}
11201146
11211147instance FromJSONKey Int where
1122− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1148+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int"
11231149
11241150-- | /WARNING:/ Only parse Integers from trusted input since an
11251151-- attacker could easily fill up the memory of the target system by
11261152-- specifying a scientific number with a big exponent like
11271153-- @1e1000000000@.
11281154instance FromJSON Integer where
1129− parseJSON = withScientific "Integral" $ pure . truncate
1155+ parseJSON = parseIntegral "Integer"
11301156 {-# INLINE parseJSON #-}
11311157
11321158instance FromJSONKey Integer where
1133− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1159+ fromJSONKey = FromJSONKeyTextParser $ parseIntegralText "Integer"
11341160
11351161instance FromJSON Natural where
11361162 parseJSON = withScientific "Natural" $ \s ->
@@ -1145,67 +1171,67 @@ instance FromJSONKey Natural where
11451171 else pure $ truncate s
11461172
11471173instance FromJSON Int8 where
1148− parseJSON = parseIntegral "Int8"
1174+ parseJSON = parseBoundedIntegral "Int8"
11491175 {-# INLINE parseJSON #-}
11501176
11511177instance FromJSONKey Int8 where
1152− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1178+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int8"
11531179
11541180instance FromJSON Int16 where
1155− parseJSON = parseIntegral "Int16"
1181+ parseJSON = parseBoundedIntegral "Int16"
11561182 {-# INLINE parseJSON #-}
11571183
11581184instance FromJSONKey Int16 where
1159− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1185+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int16"
11601186
11611187instance FromJSON Int32 where
1162− parseJSON = parseIntegral "Int32"
1188+ parseJSON = parseBoundedIntegral "Int32"
11631189 {-# INLINE parseJSON #-}
11641190
11651191instance FromJSONKey Int32 where
1166− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1192+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int32"
11671193
11681194instance FromJSON Int64 where
1169− parseJSON = parseIntegral "Int64"
1195+ parseJSON = parseBoundedIntegral "Int64"
11701196 {-# INLINE parseJSON #-}
11711197
11721198instance FromJSONKey Int64 where
1173− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1199+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int64"
11741200
11751201instance FromJSON Word where
1176− parseJSON = parseIntegral "Word"
1202+ parseJSON = parseBoundedIntegral "Word"
11771203 {-# INLINE parseJSON #-}
11781204
11791205instance FromJSONKey Word where
1180− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1206+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word"
11811207
11821208instance FromJSON Word8 where
1183− parseJSON = parseIntegral "Word8"
1209+ parseJSON = parseBoundedIntegral "Word8"
11841210 {-# INLINE parseJSON #-}
11851211
11861212instance FromJSONKey Word8 where
1187− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1213+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word8"
11881214
11891215instance FromJSON Word16 where
1190− parseJSON = parseIntegral "Word16"
1216+ parseJSON = parseBoundedIntegral "Word16"
11911217 {-# INLINE parseJSON #-}
11921218
11931219instance FromJSONKey Word16 where
1194− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1220+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word16"
11951221
11961222instance FromJSON Word32 where
1197− parseJSON = parseIntegral "Word32"
1223+ parseJSON = parseBoundedIntegral "Word32"
11981224 {-# INLINE parseJSON #-}
11991225
12001226instance FromJSONKey Word32 where
1201− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1227+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word32"
12021228
12031229instance FromJSON Word64 where
1204− parseJSON = parseIntegral "Word64"
1230+ parseJSON = parseBoundedIntegral "Word64"
12051231 {-# INLINE parseJSON #-}
12061232
12071233instance FromJSONKey Word64 where
1208− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1234+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word64"
12091235
12101236
12111237instance FromJSON Text where