Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

177 lines
3.6 KiB
C++

// Copyright (c) OWASP Project (https://www.owasp.org), 2011. All rights reserved.
// Licensed under the MIT License.
#include "TestMain.h"
#include "TestCase.h"
#if defined(__GNUC__)
# include <stdint.h>
#endif
#if !defined(CHAR_BIT)
# include <limits.h>
#endif
namespace mod_verify
{
template <typename T>
std::string type_name()
{
std::ostringstream ostm;
ostm << (std::numeric_limits<T>::is_signed ? "int" : "uint");
ostm << (sizeof(T) == 1 ? 8 : sizeof(T) * 8);
return ostm.str();
}
// ModVerifyTest2 tests (x) % (0).
template<typename T>
struct ModVerifyTest1
{
ModVerifyTest1<T>()
{
const size_t width = sizeof(T);
const size_t shift = width * CHAR_BIT - 1;
const bool expected = true;
bool divzero;
SafeInt<T> x = (T)((std::uint64_t)1 << shift);
SafeInt<T> m(0);
///////////////////////////////////////////////
try
{
T r;
r = x % m;
divzero = false;
}
catch(SafeIntException&)
{
divzero = true;
}
if(divzero != expected)
{
std::cerr << "Error in case " << type_name<T>() << ": ";
std::cerr << to_hex((T)x) << ", " << to_hex((T)m) << ", ";
std::cerr << "expected = " << (expected ? "divzero" : "no divzero") << std::endl;
}
///////////////////////////////////////////////
try
{
T r = x;
r %= m;
divzero = false;
}
catch(SafeIntException&)
{
divzero = true;
}
if(divzero != expected)
{
std::cerr << "Error in case " << type_name<T>() << ": ";
std::cerr << to_hex((T)x) << ", " << to_hex((T)m) << ", ";
std::cerr << "expected = " << (expected ? "divzero" : "no divzero") << std::endl;
}
}
};
// ModVerifyTest2 tests (INT_MIN) % (-1).
template<typename T>
struct ModVerifyTest2
{
ModVerifyTest2<T>()
{
const size_t width = sizeof(T);
const size_t shift = width * CHAR_BIT - 1;
// GCC using a native built-in int will raise SIGFPE or
// #DE. However, according to LeBlanc, SafeInt's contract
// is to return the correct mathematical result or throw.
// const bool expected = (s == Signed ? true : false);
const bool expected = false;
bool overflow;
SafeInt<T> x = (T)((std::uint64_t)1 << shift);
SafeInt<T> m((T)-1);
///////////////////////////////////////////////
try
{
T r;
r = x % m;
overflow = false;
}
catch(SafeIntException&)
{
overflow = true;
}
if(overflow != expected)
{
std::cerr << "Error in case " << type_name<T>() << ": ";
std::cerr << to_hex((T)x) << ", " << to_hex((T)m) << ", ";
std::cerr << "expected = " << (expected ? "overflow" : "no overflow") << std::endl;
}
///////////////////////////////////////////////
try
{
T r = x;
r %= m;
overflow = false;
}
catch(SafeIntException&)
{
overflow = true;
}
if(overflow != expected)
{
std::cerr << "Error in case " << type_name<T>() << ": ";
std::cerr << to_hex((T)x) << ", " << to_hex((T)m) << ", ";
std::cerr << "expected = " << (expected ? "overflow" : "no overflow") << std::endl;
}
}
};
void ModVerify()
{
std::cout << "Verifying Reduction:" << std::endl;
ModVerifyTest1<std::uint64_t> t11;
ModVerifyTest1<std::int64_t> t12;
ModVerifyTest1<std::uint32_t> t13;
ModVerifyTest1<std::int32_t> t14;
ModVerifyTest1<std::uint16_t> t15;
ModVerifyTest1<std::int16_t> t16;
ModVerifyTest1<std::uint8_t> t17;
ModVerifyTest1<std::int8_t> t18;
ModVerifyTest2<std::uint64_t> t21;
ModVerifyTest2<std::int64_t> t22;
ModVerifyTest2<std::uint32_t> t23;
ModVerifyTest2<std::int32_t> t24;
ModVerifyTest2<std::uint16_t> t25;
ModVerifyTest2<std::int16_t> t26;
ModVerifyTest2<std::uint8_t> t27;
ModVerifyTest2<std::int8_t> t28;
// Lets see.....
ModVerifyTest1<size_t> t50;
ModVerifyTest2<size_t> t51;
}
}