summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorTrent Piepho <tpiepho@gmail.com>2021-05-25 16:35:18 -0700
committerSascha Hauer <s.hauer@pengutronix.de>2021-06-09 13:52:21 +0200
commitfa36f6ee6d763d2ac00adf3cc9ac985ac13a45e9 (patch)
tree45995caada331c8ece57d74bf98709b8fd06b54e /lib
parent8da059fca282c6b165e4d11fbda5753f83541c68 (diff)
downloadbarebox-fa36f6ee6d763d2ac00adf3cc9ac985ac13a45e9.tar.gz
barebox-fa36f6ee6d763d2ac00adf3cc9ac985ac13a45e9.tar.xz
lib/math/rational.c: Fix divide by zero
If the input is out of the range of the allowed values, either larger than the largest value or closer to zero than the smallest non-zero allowed value, then a division by zero would occur. In the case of input too large, the division by zero will occur on the first iteration. The best result (largest allowed value) will be found by always choosing the semi-convergent and excluding the denominator based limit when finding it. In the case of the input too small, the division by zero will occur on the second iteration. The numerator based semi-convergent should not be calculated to avoid the division by zero. But the semi-convergent vs previous convergent test is still needed, which effectively chooses between 0 (the previous convergent) vs the smallest allowed fraction (best semi-convergent) as the result. Fixes: 323dd2c3ed0 ("lib/math/rational.c: fix possible incorrect result from rational fractions helper") Reported-by: Yiyuan Guo <yguoaz@gmail.com> Signed-off-by: Trent Piepho <tpiepho@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'lib')
-rw-r--r--lib/math/rational.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/lib/math/rational.c b/lib/math/rational.c
index e5367e6a8a..8411e912fb 100644
--- a/lib/math/rational.c
+++ b/lib/math/rational.c
@@ -78,13 +78,18 @@ void rational_best_approximation(
* found below as 't'.
*/
if ((n2 > max_numerator) || (d2 > max_denominator)) {
- unsigned long t = min((max_numerator - n0) / n1,
- (max_denominator - d0) / d1);
+ unsigned long t = ULONG_MAX;
- /* This tests if the semi-convergent is closer
- * than the previous convergent.
+ if (d1)
+ t = (max_denominator - d0) / d1;
+ if (n1)
+ t = min(t, (max_numerator - n0) / n1);
+
+ /* This tests if the semi-convergent is closer than the previous
+ * convergent. If d1 is zero there is no previous convergent as this
+ * is the 1st iteration, so always choose the semi-convergent.
*/
- if (2u * t > a || (2u * t == a && d0 * dp > d1 * d)) {
+ if (!d1 || 2u * t > a || (2u * t == a && d0 * dp > d1 * d)) {
n1 = n0 + t * n1;
d1 = d0 + t * d1;
}