@@ -178,18 +178,46 @@ parseRealFloat _ Null = pure (0/0)
178178parseRealFloat expected v = typeMismatch expected v
179179{-# INLINE parseRealFloat #-}
180180
181+truncateIntegral :: Integral a => String -> Scientific -> Parser a
182+truncateIntegral expected s
183+ | Scientific.isInteger s = pure (truncate s)
184+ | otherwise =
185+ fail $ "Floating number specified for " ++ expected ++ ": " ++ show s
186+{-# INLINE truncateIntegral #-}
187+
181188parseIntegral :: Integral a => String -> Value -> Parser a
182−parseIntegral expected = withScientific expected $ pure . truncate
189+parseIntegral expected = withScientific expected $ truncateIntegral expected
183190{-# INLINE parseIntegral #-}
184191
192+truncateBoundedIntegral :: Integral a => String -> Scientific -> Parser a
193+truncateBoundedIntegral expected s
194+ | Scientific.isInteger s =
195+ let x = truncate s
196+ in if fromIntegral x == s
197+ then pure x
198+ else fail $ "Truncating to " ++ expected ++ " cause over or underflow: " ++ show s
199+ | otherwise =
200+ fail $ "Floating number specified for " ++ expected ++ ": " ++ show s
201+{-# INLINE truncateBoundedIntegral #-}
202+
203+parseBoundedIntegral :: Integral a => String -> Value -> Parser a
204+parseBoundedIntegral expected = withScientific expected $ truncateBoundedIntegral expected
205+{-# INLINE parseBoundedIntegral #-}
206+
185207parseScientificText :: Text -> Parser Scientific
186208parseScientificText
187209 = either fail pure
188210 . A.parseOnly (A.scientific <* A.endOfInput)
189211 . T.encodeUtf8
190212
191−parseIntegralText :: Integral a => Text -> Parser a
192−parseIntegralText t = truncate <$> parseScientificText t
213+parseIntegralText :: Integral a => String -> Text -> Parser a
214+parseIntegralText expected t =
215+ parseScientificText t >>= truncateIntegral expected
216+{-# INLINE parseIntegralText #-}
217+
218+parseBoundedIntegralText :: Integral a => String -> Text -> Parser a
219+parseBoundedIntegralText expected t =
220+ parseScientificText t >>= truncateBoundedIntegral expected
193221
194222parseOptionalFieldWith :: (Value -> Parser (Maybe a))
195223 -> Object -> Text -> Parser (Maybe a)
@@ -1115,22 +1143,22 @@ instance HasResolution a => FromJSON (Fixed a) where
11151143 {-# INLINE parseJSON #-}
11161144
11171145instance FromJSON Int where
1118− parseJSON = parseIntegral "Int"
1146+ parseJSON = parseBoundedIntegral "Int"
11191147 {-# INLINE parseJSON #-}
11201148
11211149instance FromJSONKey Int where
1122− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1150+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int"
11231151
11241152-- | /WARNING:/ Only parse Integers from trusted input since an
11251153-- attacker could easily fill up the memory of the target system by
11261154-- specifying a scientific number with a big exponent like
11271155-- @1e1000000000@.
11281156instance FromJSON Integer where
1129− parseJSON = withScientific "Integral" $ pure . truncate
1157+ parseJSON = parseIntegral "Integer"
11301158 {-# INLINE parseJSON #-}
11311159
11321160instance FromJSONKey Integer where
1133− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1161+ fromJSONKey = FromJSONKeyTextParser $ parseIntegralText "Integer"
11341162
11351163instance FromJSON Natural where
11361164 parseJSON = withScientific "Natural" $ \s ->
@@ -1145,67 +1173,67 @@ instance FromJSONKey Natural where
11451173 else pure $ truncate s
11461174
11471175instance FromJSON Int8 where
1148− parseJSON = parseIntegral "Int8"
1176+ parseJSON = parseBoundedIntegral "Int8"
11491177 {-# INLINE parseJSON #-}
11501178
11511179instance FromJSONKey Int8 where
1152− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1180+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int8"
11531181
11541182instance FromJSON Int16 where
1155− parseJSON = parseIntegral "Int16"
1183+ parseJSON = parseBoundedIntegral "Int16"
11561184 {-# INLINE parseJSON #-}
11571185
11581186instance FromJSONKey Int16 where
1159− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1187+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int16"
11601188
11611189instance FromJSON Int32 where
1162− parseJSON = parseIntegral "Int32"
1190+ parseJSON = parseBoundedIntegral "Int32"
11631191 {-# INLINE parseJSON #-}
11641192
11651193instance FromJSONKey Int32 where
1166− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1194+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int32"
11671195
11681196instance FromJSON Int64 where
1169− parseJSON = parseIntegral "Int64"
1197+ parseJSON = parseBoundedIntegral "Int64"
11701198 {-# INLINE parseJSON #-}
11711199
11721200instance FromJSONKey Int64 where
1173− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1201+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int64"
11741202
11751203instance FromJSON Word where
1176− parseJSON = parseIntegral "Word"
1204+ parseJSON = parseBoundedIntegral "Word"
11771205 {-# INLINE parseJSON #-}
11781206
11791207instance FromJSONKey Word where
1180− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1208+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word"
11811209
11821210instance FromJSON Word8 where
1183− parseJSON = parseIntegral "Word8"
1211+ parseJSON = parseBoundedIntegral "Word8"
11841212 {-# INLINE parseJSON #-}
11851213
11861214instance FromJSONKey Word8 where
1187− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1215+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word8"
11881216
11891217instance FromJSON Word16 where
1190− parseJSON = parseIntegral "Word16"
1218+ parseJSON = parseBoundedIntegral "Word16"
11911219 {-# INLINE parseJSON #-}
11921220
11931221instance FromJSONKey Word16 where
1194− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1222+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word16"
11951223
11961224instance FromJSON Word32 where
1197− parseJSON = parseIntegral "Word32"
1225+ parseJSON = parseBoundedIntegral "Word32"
11981226 {-# INLINE parseJSON #-}
11991227
12001228instance FromJSONKey Word32 where
1201− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1229+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word32"
12021230
12031231instance FromJSON Word64 where
1204− parseJSON = parseIntegral "Word64"
1232+ parseJSON = parseBoundedIntegral "Word64"
12051233 {-# INLINE parseJSON #-}
12061234
12071235instance FromJSONKey Word64 where
1208− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1236+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word64"
12091237
12101238
12111239instance FromJSON Text where