Fix overflow error in integer_parser. (#417)
Fixes #290. Checking for overflow should be done before integer overflows. There are two checks: (result > limit / base) is used for limits greater than rounded up to base, e.g. for 65535 it will activate for 65540 and higher. (result * base > limit - digit) is used for limit+1 to limit+n below next base rounded number, e.g. 65536 up to 65539.
This commit is contained in:
parent
7bf29108d5
commit
e84ab5f67c
@ -27,6 +27,7 @@ THE SOFTWARE.
|
||||
#ifndef CXXOPTS_HPP_INCLUDED
|
||||
#define CXXOPTS_HPP_INCLUDED
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <limits>
|
||||
@ -972,13 +973,26 @@ integer_parser(const std::string& text, T& value)
|
||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
||||
}
|
||||
|
||||
const US next = static_cast<US>(result * base + digit);
|
||||
if (result > next)
|
||||
US limit = 0;
|
||||
if (negative)
|
||||
{
|
||||
limit = static_cast<US>(std::abs(static_cast<intmax_t>(std::numeric_limits<T>::min())));
|
||||
}
|
||||
else
|
||||
{
|
||||
limit = std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
if (base != 0 && result > limit / base)
|
||||
{
|
||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
||||
}
|
||||
if (result * base > limit - digit)
|
||||
{
|
||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
||||
}
|
||||
|
||||
result = next;
|
||||
result = static_cast<US>(result * base + digit);
|
||||
}
|
||||
|
||||
detail::check_signed_range<T>(negative, result, text);
|
||||
|
@ -552,7 +552,11 @@ TEST_CASE("Overflow on boundary", "[integer]")
|
||||
using namespace cxxopts::values;
|
||||
|
||||
int8_t si;
|
||||
int16_t si16;
|
||||
int64_t si64;
|
||||
uint8_t ui;
|
||||
uint16_t ui16;
|
||||
uint64_t ui64;
|
||||
|
||||
CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::exceptions::incorrect_argument_type);
|
||||
@ -560,6 +564,20 @@ TEST_CASE("Overflow on boundary", "[integer]")
|
||||
CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::exceptions::incorrect_argument_type);
|
||||
|
||||
CHECK_THROWS_AS((integer_parser("65536", ui16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("75536", ui16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("32768", si16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-32769", si16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-42769", si16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-75536", si16)), cxxopts::exceptions::incorrect_argument_type);
|
||||
|
||||
CHECK_THROWS_AS((integer_parser("18446744073709551616", ui64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("28446744073709551616", ui64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("9223372036854775808", si64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-9223372036854775809", si64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-10223372036854775809", si64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
CHECK_THROWS_AS((integer_parser("-28446744073709551616", si64)), cxxopts::exceptions::incorrect_argument_type);
|
||||
}
|
||||
|
||||
TEST_CASE("Integer overflow", "[options]")
|
||||
|
Loading…
Reference in New Issue
Block a user