Add scaling to fix b/278065963.
(Minor changes are possible in potential overflow conditions.)
STATS_CHANGED
Bug: b/278065963
Change-Id: I78b35feb1e2dc3012fb3ee341c17c0ffb41ed33c
diff --git a/av1/encoder/pickrst.c b/av1/encoder/pickrst.c
index 972327a..a404663 100644
--- a/av1/encoder/pickrst.c
+++ b/av1/encoder/pickrst.c
@@ -1097,15 +1097,41 @@
b[i - 1] = c;
}
}
+
+ // b/278065963: The multiplies
+ // c / 256 * A[k * stride + j] / cd * 256
+ // and
+ // c / 256 * b[k] / cd * 256
+ // within Gaussian elimination can cause a signed integer overflow. Rework
+ // the multiplies so that larger scaling is used without significantly
+ // impacting the overall precision.
+ //
+ // Precision guidance:
+ // scale_threshold: Pick as high as possible.
+ // For max_abs_akj >= scale_threshold scenario:
+ // scaler_A: Pick as low as possible. Needed for A[(i + 1) * stride + j].
+ // scaler_c: Pick as low as possible while maintaining scaler_c >=
+ // (1 << 7). Needed for A[(i + 1) * stride + j] and b[i + 1].
+ int64_t max_abs_akj = 0;
+ for (int j = 0; j < n; j++) {
+ const int64_t abs_akj = llabs(A[k * stride + j]);
+ if (abs_akj > max_abs_akj) max_abs_akj = abs_akj;
+ }
+ const int scale_threshold = 1 << 22;
+ const int scaler_A = max_abs_akj < scale_threshold ? 1 : (1 << 4);
+ const int scaler_c = max_abs_akj < scale_threshold ? 1 : (1 << 7);
+ const int scaler = scaler_c * scaler_A;
+
// Forward elimination (convert A to row-echelon form)
for (int i = k; i < n - 1; i++) {
if (A[k * stride + k] == 0) return 0;
- const int64_t c = A[(i + 1) * stride + k];
+ const int64_t c = A[(i + 1) * stride + k] / scaler_c;
const int64_t cd = A[k * stride + k];
for (int j = 0; j < n; j++) {
- A[(i + 1) * stride + j] -= c / 256 * A[k * stride + j] / cd * 256;
+ A[(i + 1) * stride + j] -=
+ A[k * stride + j] / scaler_A * c / cd * scaler;
}
- b[i + 1] -= c / 256 * b[k] / cd * 256;
+ b[i + 1] -= c * b[k] / cd * scaler_c;
}
}
// Back-substitution