Check for int32_t overflows in 'clap' code

Check if a uint32_t variable is <= INT32_MAX before casting it to
int32_t.

Perform the arithmetic operations in int64_t and then check for int32_t
overflows.

Change clapFractionCD(), clapFractionAdd(), and clapFractionSub() to
return avifBool. They return AVIF_FALSE if any arithmetic operation
overflows int32_t.
diff --git a/src/avif.c b/src/avif.c
index f21c42a..bc238f2 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -435,43 +435,66 @@
     }
 }
 
+static avifBool overflowsInt32(int64_t x)
+{
+    return (x < INT32_MIN) || (x > INT32_MAX);
+}
+
 // Make the fractions have a common denominator
-static void clapFractionCD(clapFraction * a, clapFraction * b)
+static avifBool clapFractionCD(clapFraction * a, clapFraction * b)
 {
     clapFractionSimplify(a);
     clapFractionSimplify(b);
     if (a->d != b->d) {
-        const int32_t ad = a->d;
-        const int32_t bd = b->d;
-        a->n *= bd;
-        a->d *= bd;
-        b->n *= ad;
-        b->d *= ad;
+        const int64_t ad = a->d;
+        const int64_t bd = b->d;
+        const int64_t anNew = a->n * bd;
+        const int64_t adNew = a->d * bd;
+        const int64_t bnNew = b->n * ad;
+        const int64_t bdNew = b->d * ad;
+        if (overflowsInt32(anNew) || overflowsInt32(adNew) || overflowsInt32(bnNew) || overflowsInt32(bdNew)) {
+            return AVIF_FALSE;
+        }
+        a->n = (int32_t)anNew;
+        a->d = (int32_t)adNew;
+        b->n = (int32_t)bnNew;
+        b->d = (int32_t)bdNew;
     }
+    return AVIF_TRUE;
 }
 
-static clapFraction clapFractionAdd(clapFraction a, clapFraction b)
+static avifBool clapFractionAdd(clapFraction a, clapFraction b, clapFraction * result)
 {
-    clapFractionCD(&a, &b);
+    if (!clapFractionCD(&a, &b)) {
+        return AVIF_FALSE;
+    }
 
-    clapFraction result;
-    result.n = a.n + b.n;
-    result.d = a.d;
+    const int64_t resultN = (int64_t)a.n + b.n;
+    if (overflowsInt32(resultN)) {
+        return AVIF_FALSE;
+    }
+    result->n = (int32_t)resultN;
+    result->d = a.d;
 
-    clapFractionSimplify(&result);
-    return result;
+    clapFractionSimplify(result);
+    return AVIF_TRUE;
 }
 
-static clapFraction clapFractionSub(clapFraction a, clapFraction b)
+static avifBool clapFractionSub(clapFraction a, clapFraction b, clapFraction * result)
 {
-    clapFractionCD(&a, &b);
+    if (!clapFractionCD(&a, &b)) {
+        return AVIF_FALSE;
+    }
 
-    clapFraction result;
-    result.n = a.n - b.n;
-    result.d = a.d;
+    const int64_t resultN = (int64_t)a.n - b.n;
+    if (overflowsInt32(resultN)) {
+        return AVIF_FALSE;
+    }
+    result->n = (int32_t)resultN;
+    result->d = a.d;
 
-    clapFractionSimplify(&result);
-    return result;
+    clapFractionSimplify(result);
+    return AVIF_TRUE;
 }
 
 static avifBool avifCropRectIsValid(const avifCropRect * cropRect, uint32_t imageW, uint32_t imageH, avifPixelFormat yuvFormat, avifDiagnostics * diag)
@@ -563,17 +586,29 @@
     clapFraction horizOff;
     horizOff.n = horizOffN;
     horizOff.d = horizOffD;
-    clapFraction croppedCenterX = clapFractionAdd(uncroppedCenterX, horizOff);
+    clapFraction croppedCenterX;
+    if (!clapFractionAdd(uncroppedCenterX, horizOff, &croppedCenterX)) {
+        avifDiagnosticsPrintf(diag, "[Strict] croppedCenterX overflowed");
+        return AVIF_FALSE;
+    }
 
     clapFraction vertOff;
     vertOff.n = vertOffN;
     vertOff.d = vertOffD;
-    clapFraction croppedCenterY = clapFractionAdd(uncroppedCenterY, vertOff);
+    clapFraction croppedCenterY;
+    if (!clapFractionAdd(uncroppedCenterY, vertOff, &croppedCenterY)) {
+        avifDiagnosticsPrintf(diag, "[Strict] croppedCenterY overflowed");
+        return AVIF_FALSE;
+    }
 
     clapFraction halfW;
     halfW.n = clapW;
     halfW.d = 2;
-    clapFraction cropX = clapFractionSub(croppedCenterX, halfW);
+    clapFraction cropX;
+    if (!clapFractionSub(croppedCenterX, halfW, &cropX)) {
+        avifDiagnosticsPrintf(diag, "[Strict] cropX overflowed");
+        return AVIF_FALSE;
+    }
     if ((cropX.n % cropX.d) != 0) {
         avifDiagnosticsPrintf(diag, "[Strict] calculated crop X offset %d/%d is not an integer", cropX.n, cropX.d);
         return AVIF_FALSE;
@@ -582,7 +617,11 @@
     clapFraction halfH;
     halfH.n = clapH;
     halfH.d = 2;
-    clapFraction cropY = clapFractionSub(croppedCenterY, halfH);
+    clapFraction cropY;
+    if (!clapFractionSub(croppedCenterY, halfH, &cropY)) {
+        avifDiagnosticsPrintf(diag, "[Strict] cropY overflowed");
+        return AVIF_FALSE;
+    }
     if ((cropY.n % cropY.d) != 0) {
         avifDiagnosticsPrintf(diag, "[Strict] calculated crop Y offset %d/%d is not an integer", cropY.n, cropY.d);
         return AVIF_FALSE;
@@ -611,16 +650,45 @@
         return AVIF_FALSE;
     }
 
-    clapFraction uncroppedCenterX = calcCenter(imageW);
-    clapFraction uncroppedCenterY = calcCenter(imageH);
+    if ((imageW > INT32_MAX) || (imageH > INT32_MAX)) {
+        avifDiagnosticsPrintf(diag, "[Strict] image width %u or height %u is greater than INT32_MAX", imageW, imageH);
+        return AVIF_FALSE;
+    }
+    clapFraction uncroppedCenterX = calcCenter((int32_t)imageW);
+    clapFraction uncroppedCenterY = calcCenter((int32_t)imageH);
 
-    clapFraction croppedCenterX = calcCenter(cropRect->width);
-    croppedCenterX.n += cropRect->x * croppedCenterX.d;
-    clapFraction croppedCenterY = calcCenter(cropRect->height);
-    croppedCenterY.n += cropRect->y * croppedCenterY.d;
+    if ((cropRect->width > INT32_MAX) || (cropRect->height > INT32_MAX)) {
+        avifDiagnosticsPrintf(diag,
+                              "[Strict] crop rect width %u or height %u is greater than INT32_MAX",
+                              cropRect->width,
+                              cropRect->height);
+        return AVIF_FALSE;
+    }
+    clapFraction croppedCenterX = calcCenter((int32_t)cropRect->width);
+    const int64_t croppedCenterXN = croppedCenterX.n + (int64_t)cropRect->x * croppedCenterX.d;
+    if (overflowsInt32(croppedCenterXN)) {
+        avifDiagnosticsPrintf(diag, "[Strict] croppedCenterX overflowed");
+        return AVIF_FALSE;
+    }
+    croppedCenterX.n = (int32_t)croppedCenterXN;
+    clapFraction croppedCenterY = calcCenter((int32_t)cropRect->height);
+    const int64_t croppedCenterYN = croppedCenterY.n + (int64_t)cropRect->y * croppedCenterY.d;
+    if (overflowsInt32(croppedCenterYN)) {
+        avifDiagnosticsPrintf(diag, "[Strict] croppedCenterY overflowed");
+        return AVIF_FALSE;
+    }
+    croppedCenterY.n = (int32_t)croppedCenterYN;
 
-    clapFraction horizOff = clapFractionSub(croppedCenterX, uncroppedCenterX);
-    clapFraction vertOff = clapFractionSub(croppedCenterY, uncroppedCenterY);
+    clapFraction horizOff;
+    if (!clapFractionSub(croppedCenterX, uncroppedCenterX, &horizOff)) {
+        avifDiagnosticsPrintf(diag, "[Strict] horizOff overflowed");
+        return AVIF_FALSE;
+    }
+    clapFraction vertOff;
+    if (!clapFractionSub(croppedCenterY, uncroppedCenterY, &vertOff)) {
+        avifDiagnosticsPrintf(diag, "[Strict] vertOff overflowed");
+        return AVIF_FALSE;
+    }
 
     clap->widthN = cropRect->width;
     clap->widthD = 1;