Skip to content

Commit

Permalink
Merge pull request #1843 from Exiv2/mergify/bp/main/pr-1840
Browse files Browse the repository at this point in the history
Check that the float is within the range of an int before casting (backport #1840)
  • Loading branch information
kevinbackhouse authored Aug 6, 2021
2 parents 66259b1 + 7c2ab1d commit 330483a
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
26 changes: 14 additions & 12 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <sstream>
#include <utility>
#include <cctype>
#include <climits>
#include <ctime>
#include <cstdio>
#include <cstdlib>
Expand Down Expand Up @@ -670,27 +671,28 @@ namespace Exiv2 {

Rational floatToRationalCast(float f)
{
#if defined(_MSC_VER) && _MSC_VER < 1800
if (!_finite(f)) {
#else
if (!std::isfinite(f)) {
#endif
return {f > 0 ? 1 : -1, 0};

// Convert f to double because it simplifies the "in_range" check
// below. (INT_MAX can be represented accurately as a double, but
// gets rounded when it's converted to float.)
const double d = f;
const bool in_range = INT_MIN <= d && d <= INT_MAX;
if (!in_range) {
return {d > 0 ? 1 : -1, 0};
}
// Beware: primitive conversion algorithm
int32_t den = 1000000;
const long f_as_long = static_cast<long>(f);
if (Safe::abs(f_as_long) > 2147) {
const long d_as_long = static_cast<long>(d);
if (Safe::abs(d_as_long) > 2147) {
den = 10000;
}
if (Safe::abs(f_as_long) > 214748) {
if (Safe::abs(d_as_long) > 214748) {
den = 100;
}
if (Safe::abs(f_as_long) > 21474836) {
if (Safe::abs(d_as_long) > 21474836) {
den = 1;
}
const float rnd = f >= 0 ? 0.5F : -0.5F;
const auto nom = static_cast<int32_t>(f * den + rnd);
const auto nom = static_cast<int32_t>(std::round(d * den));
const int32_t g = gcd(nom, den);

return {nom / g, den / g};
Expand Down
Binary file added test/data/issue_1838_poc.crw
Binary file not shown.
17 changes: 17 additions & 0 deletions tests/bugfixes/github/test_issue_1838.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-

from system_tests import CaseMeta, path, check_no_ASAN_UBSAN_errors

class FloatToRationalCastOutOfRange(metaclass=CaseMeta):
"""
Test for the bug described in:
https://github.com/Exiv2/exiv2/issues/1838
"""
url = "https://github.com/Exiv2/exiv2/issues/1838"

filename = path("$data_path/issue_1838_poc.crw")
commands = ["$exiv2 $filename"]
stderr = [""]
retval = [0]

compare_stdout = check_no_ASAN_UBSAN_errors

0 comments on commit 330483a

Please sign in to comment.