Repository: python-jsonschema/jsonschema
Issue: Unhandled `OverflowError` when checking `multipleOf` with large numbers

```python
>>> jsonschema.validate(1e308, {"type": "integer", "multipleOf": 0.5})

Traceback (most recent call last):
    ...
    File "jsonschema/_validators.py", line 170, in multipleOf
        failed = int(quotient) != quotient
OverflowError: cannot convert float infinity to integer
```

So the specific problem is that while `1e308` is finite, `1e308 / 0.5` overflows to infinity and then this raises an error when `int(inf)` is called.  (it's a floating-point issue, but at least it's not "division doesn't work like real numbers"!)

I do consider this a bug because attempting to validate a well-formed instance with a well-formed schema should return either True or False, not raise an error.  You could note that the spec allows implementations to limit the range of numbers they accept, but if so I'd still want a better error message and more specific exception type.

Of course, the question of *which* this should return is a somewhat ambiguous...

- `0.5` *is* exactly representable as a float, `1e308 ==int(1e308)`, and obviously integers are all multiples of `0.5`.  My personal preference is therefore to call this instance valid and that's what https://github.com/Julian/jsonschema/compare/master...Zac-HD:multipleOf-overflow would do.

- [The spec for `multipleOf`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.6.2.1) just says "A numeric instance is valid only if division by this keyword's value results in an integer"; overflowing to infinity is not an integer, and therefore the instance is invalid.  That could easily be implemented with `except OverflowError: failed = True`.

In either case, we should probably also add an optional test to the upstream test suite...

Changed files:
jsonschema/tests/test_jsonschema_test_suite.py, jsonschema/_validators.py

diff --git a/jsonschema/_validators.py b/jsonschema/_validators.py
index d7097ff..7e8c95a 100644
--- a/jsonschema/_validators.py
+++ b/jsonschema/_validators.py
@@ -1,3 +1,4 @@
+from fractions import Fraction
 import re
 
 from jsonschema._utils import (
@@ -166,7 +167,18 @@ def multipleOf(validator, dB, instance, schema):
 
     if isinstance(dB, float):
         quotient = instance / dB
-        failed = int(quotient) != quotient
+        try:
+            failed = int(quotient) != quotient
+        except OverflowError:
+            # When `instance` is large and `dB` is less than one, quotient can
+            # overflow to infinity; and then casting to int raises an error.
+            #
+            # In this case we fall back to Fraction logic, which is exact and
+            # cannot overflow.  The performance is also acceptable: we try the
+            # fast all-float option first, and we know that fraction(dB) can have
+            # at most a few hundred digits in each part.  The worst-case slowdown
+            # is therefore for already-slow enormous integers or Decimals.
+            failed = (Fraction(instance) / Fraction(dB)).denominator != 1
     else:
         failed = instance % dB
 
diff --git a/jsonschema/tests/test_jsonschema_test_suite.py b/jsonschema/tests/test_jsonschema_test_suite.py
index d6721b5..0f9698a 100644
--- a/jsonschema/tests/test_jsonschema_test_suite.py
+++ b/jsonschema/tests/test_jsonschema_test_suite.py
@@ -161,7 +161,6 @@ TestDraft4 = DRAFT4.to_unittest_testcase(
     DRAFT4.tests(),
     DRAFT4.format_tests(),
     DRAFT4.optional_tests_of(name="bignum"),
-    DRAFT4.optional_tests_of(name="float-overflow"),
     DRAFT4.optional_tests_of(name="non-bmp-regex"),
     DRAFT4.optional_tests_of(name="zeroTerminatedFloats"),
     Validator=Draft4Validator,
@@ -235,18 +234,6 @@ TestDraft4 = DRAFT4.to_unittest_testcase(
             subject="uniqueItems",
             description='{"a": true} and {"a": 1} are unique',
         )(test)
-        or skip(
-            message=bug(743),
-            subject="float-overflow",
-        )(test)
-        or skip(
-            message=bug(743),
-            subject="multipleOf",
-            description=(
-                "always invalid, but naive implementations "
-                "may raise an overflow error"
-            ),
-        )(test)
     ),
 )
 
@@ -255,7 +242,6 @@ TestDraft6 = DRAFT6.to_unittest_testcase(
     DRAFT6.tests(),
     DRAFT6.format_tests(),
     DRAFT6.optional_tests_of(name="bignum"),
-    DRAFT6.optional_tests_of(name="float-overflow"),
     DRAFT6.optional_tests_of(name="non-bmp-regex"),
     Validator=Draft6Validator,
     format_checker=draft6_format_checker,
@@ -348,18 +334,6 @@ TestDraft6 = DRAFT6.to_unittest_testcase(
             subject="const",
             case_description='const with {"a": true} does not match {"a": 1}',
         )(test)
-        or skip(
-            message=bug(743),
-            subject="float-overflow",
-        )(test)
-        or skip(
-            message=bug(743),
-            subject="multipleOf",
-            description=(
-                "always invalid, but naive implementations "
-                "may raise an overflow error"
-            ),
-        )(test)
     ),
 )
 
@@ -368,7 +342,6 @@ TestDraft7 = DRAFT7.to_unittest_testcase(
     DRAFT7.tests(),
     DRAFT7.format_tests(),
     DRAFT7.optional_tests_of(name="bignum"),
-    DRAFT7.optional_tests_of(name="float-overflow"),
     DRAFT7.optional_tests_of(name="content"),
     DRAFT7.optional_tests_of(name="non-bmp-regex"),
     Validator=Draft7Validator,
@@ -484,18 +457,6 @@ TestDraft7 = DRAFT7.to_unittest_testcase(
             subject="const",
             case_description='const with {"a": true} does not match {"a": 1}',
         )(test)
-        or skip(
-            message=bug(743),
-            subject="float-overflow",
-        )(test)
-        or skip(
-            message=bug(743),
-            subject="multipleOf",
-            description=(
-                "always invalid, but naive implementations "
-                "may raise an overflow error"
-            ),
-        )(test)
     ),
 )