fix(feat): Multiplication result converted to larger type
https://github.com/ValveSoftware/GameNetworkingSockets/blob/725e273c7442bac7a8bc903c0b210b1c15c34d92/src/tier1/utlmemory.cpp#L21-L21
fix the issue need to ensure that the multiplication is performed using a larger type (e.g., size_t) to prevent overflow. This can be achieved by explicitly casting one of the operands to size_t before the multiplication. This ensures that the multiplication is performed in the larger type, avoiding overflow.
The specific change involves modifying line 21 to cast m_nAllocationCount or m_unSizeOfElements to size_t before the multiplication. This change is localized and does not affect the rest of the code's functionality.
The product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. This occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may become a very small or negative number.
This rule finds code that converts the result of an integer multiplication to a larger type. Since the conversion applies after the multiplication, arithmetic overflow may still occur. The rule flags every multiplication of two non-constant integer expressions that is (explicitly or implicitly) converted to a larger integer type. The conversion is an indication that the expression would produce a result that would be too large to fit in the smaller integer type.
int i = 2000000000;
long j = i * i; //Wrong: due to overflow on the multiplication between ints,
//will result to j being -1651507200, not 4000000000000000000
long k = (long) i * i; //Correct: the multiplication is done on longs instead of ints,
//and will not overflow
long l = static_cast<long>(i) * i; //Correct: modern C++
References
Multiplicative Operators and the Modulus Operator Integer overflow CWE-190 CWE-192 CWE-197 CWE-681
ping @zpostfacto lets merged this pull-request for patch the vulnerable.
CUtlMemoryBase::CUtlMemoryBase(int nSizeOfType, int nGrowSize, int nInitAllocationCount)
: m_pMemory(nullptr),
m_nAllocationCount(nInitAllocationCount),
m_nGrowSize(nGrowSize),
m_unSizeOfElements(nSizeOfType)
{
if (m_unSizeOfElements <= 0)
throw std::invalid_argument("Element size must be positive");
if (m_nGrowSize < 0)
throw std::invalid_argument("Grow size cannot be negative");
if (m_nAllocationCount > 0)
{
if (static_cast<size_t>(m_nAllocationCount) >
std::numeric_limits<size_t>::max() / static_cast<size_t>(m_unSizeOfElements))
{
throw std::overflow_error("Allocation size overflow");
}
size_t totalSize = static_cast<size_t>(m_nAllocationCount) * static_cast<size_t>(m_unSizeOfElements);
UTLMEMORY_TRACK_ALLOC();
m_pMemory = PvAlloc(totalSize);
if (!m_pMemory)
{
throw std::bad_alloc();
}
}
}