2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-05-29 08:20:53 +00:00

Detect integer overflow/underflow

This commit is contained in:
Jay Berkenbilt 2017-08-29 12:21:29 -04:00
parent d7d446e0b8
commit 6d46346eb9
4 changed files with 110 additions and 2 deletions

View File

@ -29,8 +29,12 @@ namespace QUtil
QPDF_DLL
std::string double_to_string(double, int decimal_places = 0);
// These string to number methods throw std::runtime_error on
// underflow/overflow.
QPDF_DLL
long long string_to_ll(char const* str);
QPDF_DLL
int string_to_int(char const* str);
// Pipeline's write method wants unsigned char*, but we often have
// some other type of string. These methods do combinations of

View File

@ -81,11 +81,40 @@ QUtil::double_to_string(double num, int decimal_places)
long long
QUtil::string_to_ll(char const* str)
{
errno = 0;
#ifdef _MSC_VER
return _strtoi64(str, 0, 10);
long long result = _strtoi64(str, 0, 10);
#else
return strtoll(str, 0, 10);
long long result = strtoll(str, 0, 10);
#endif
if (errno == ERANGE)
{
throw std::runtime_error(
std::string("overflow/underflow converting ") + str
+ " to 64-bit integer");
}
return result;
}
int
QUtil::string_to_int(char const* str)
{
errno = 0;
long long_val = strtol(str, 0, 10);
if (errno == ERANGE)
{
throw std::runtime_error(
std::string("overflow/underflow converting ") + str
+ " to long integer");
}
int result = static_cast<int>(long_val);
if (static_cast<long>(result) != long_val)
{
throw std::runtime_error(
std::string("overflow/underflow converting ") + str
+ " to integer");
}
return result;
}
unsigned char*

View File

@ -14,6 +14,14 @@
one
7
compare okay
-2147483648 to int: PASSED
2147483647 to int: PASSED
2147483648 to int threw: PASSED
-2147483649 to int threw: PASSED
9999999999999999999999999 to int threw: PASSED
2147483648 to int: PASSED
-2147483649 to int: PASSED
99999999999999999999999999999999999999999999999999 to int threw: PASSED
----
before remove
exception: remove file: No such file or directory

View File

@ -6,6 +6,7 @@
#include <qpdf/QUtil.hh>
#include <qpdf/PointerHolder.hh>
#include <string.h>
#include <limits.h>
#ifdef _WIN32
# include <io.h>
@ -13,6 +14,57 @@
# include <unistd.h>
#endif
template <class int_T>
void test_to_number(char const* str, int_T wanted, bool error,
int_T (*fn)(char const*))
{
bool threw = false;
bool worked = false;
int_T result = 0;
try
{
result = fn(str);
worked = (wanted == result);
}
catch (std::runtime_error)
{
threw = true;
}
if (threw)
{
if (error)
{
std::cout << str << " to int threw: PASSED" << std::endl;
}
else
{
std::cout << str << " to int threw but wanted "
<< wanted << std::endl;
}
}
else
{
if (worked)
{
std::cout << str << " to int: PASSED" << std::endl;
}
else
{
std::cout << str << " to int failed; got " << result << std::endl;
}
}
}
void test_to_int(char const* str, int wanted, bool error)
{
test_to_number(str, wanted, error, QUtil::string_to_int);
}
void test_to_ll(char const* str, long long wanted, bool error)
{
test_to_number(str, wanted, error, QUtil::string_to_ll);
}
void string_conversion_test()
{
std::cout << QUtil::int_to_string(16059) << std::endl
@ -44,6 +96,21 @@ void string_conversion_test()
std::cout << "compare failed" << std::endl;
}
delete [] tmp;
std::string int_max_str = QUtil::int_to_string(INT_MAX);
std::string int_min_str = QUtil::int_to_string(INT_MIN);
long long int_max_plus_1 = static_cast<long long>(INT_MAX) + 1;
long long int_min_minus_1 = static_cast<long long>(INT_MIN) - 1;
std::string int_max_plus_1_str = QUtil::int_to_string(int_max_plus_1);
std::string int_min_minus_1_str = QUtil::int_to_string(int_min_minus_1);
test_to_int(int_min_str.c_str(), INT_MIN, false);
test_to_int(int_max_str.c_str(), INT_MAX, false);
test_to_int(int_max_plus_1_str.c_str(), 0, true);
test_to_int(int_min_minus_1_str.c_str(), 0, true);
test_to_int("9999999999999999999999999", 0, true);
test_to_ll(int_max_plus_1_str.c_str(), int_max_plus_1, false);
test_to_ll(int_min_minus_1_str.c_str(), int_min_minus_1, false);
test_to_ll("99999999999999999999999999999999999999999999999999", 0, true);
}
void os_wrapper_test()