Documentation Index
Fetch the complete documentation index at: https://mintlify.com/MicrosoftDocs/cpp-docs/llms.txt
Use this file to discover all available pages before exploring further.
Integer overflow is one of the most pervasive and dangerous bugs in systems programming. When a signed integer overflows in C++, the behavior is undefined; for unsigned integers it wraps around silently. Both conditions can corrupt data, bypass security checks (e.g., a computed buffer size that wraps to zero), or lead to exploitable vulnerabilities. The SafeInt library is a portable, header-only C++ template library that wraps integer types with overflow checking on every arithmetic and comparison operation. It is available for use with MSVC, GCC, and Clang, and ships as part of the Visual Studio installation.
What SafeInt Is (and Is Not)
SafeInt is not a big-integer library — it does not extend precision beyond the native type. It is a checked arithmetic library: every operation on a SafeInt<T> value checks whether the result would overflow the range of T, and if so, throws a SafeIntException or invokes a custom error handler, rather than producing a silently wrong result.
The latest version of the source is available at https://github.com/dcleblanc/SafeInt. To use it:
// Clone the repo and include the header directly (header-only, no compilation step)
#include "SafeInt.hpp"
Basic Usage
SafeInt<T> is a drop-in wrapper around any integer type T. It overloads all arithmetic and comparison operators:
#include "SafeInt.hpp"
#include <iostream>
int main() {
// Basic construction and assignment
SafeInt<int> a = 100;
SafeInt<int> b = 200;
SafeInt<int> sum = a + b; // Checked addition
SafeInt<int> product = a * b; // Checked multiplication
std::cout << "sum = " << (int)sum << "\n"; // 300
std::cout << "product = " << (int)product << "\n"; // 20000
// Unsigned types work the same way
SafeInt<unsigned int> ua = 100u;
SafeInt<unsigned int> ub = 50u;
SafeInt<unsigned int> udiff = ua - ub; // Safe: 50
std::cout << "udiff = " << (unsigned)udiff << "\n";
// Comparisons across different integer types
SafeInt<int> signed_val = -1;
SafeInt<unsigned int> unsigned_val = 1u;
// This comparison is safe: SafeInt handles signed/unsigned correctly
bool less = signed_val < unsigned_val; // true (correct: -1 < 1)
std::cout << "-1 < 1u: " << less << "\n";
return 0;
}
Raw C++ comparison of a negative int and an unsigned int gives wrong results due to the implicit conversion of the signed value to unsigned (making -1 appear larger than 1u). SafeInt handles this correctly by performing type-aware comparisons.
Detecting Overflow with SafeIntException
When an overflow is detected, SafeInt throws SafeIntException by default. You can catch it to handle the error gracefully:
#include "SafeInt.hpp"
#include <iostream>
#include <stdexcept>
int main() {
try {
SafeInt<int> maxval = INT_MAX; // 2,147,483,647
SafeInt<int> result = maxval + 1; // OVERFLOW — throws SafeIntException
std::cout << "Should not reach here\n";
}
catch (const SafeIntException& e) {
std::cout << "Caught SafeIntException: overflow detected!\n";
std::cout << "Error code: " << e.m_code << "\n";
}
try {
SafeInt<unsigned int> zero = 0u;
SafeInt<unsigned int> result = zero - 1u; // Underflow — throws
std::cout << "Should not reach here\n";
}
catch (const SafeIntException& e) {
std::cout << "Caught SafeIntException: underflow detected!\n";
}
// Multiplication overflow
try {
SafeInt<int> big = 100000;
SafeInt<int> result = big * big; // 10^10 — overflows int
std::cout << "Should not reach here\n";
}
catch (const SafeIntException& e) {
std::cout << "Caught SafeIntException: multiplication overflow!\n";
}
std::cout << "All overflow cases handled.\n";
return 0;
}
Before and After: Security-Critical Allocation
Integer overflow in size calculations is a classic vulnerability pattern. SafeInt eliminates it:
Unsafe (Classic C++)
Safe (SafeInt)
// DANGEROUS: if count or element_size are attacker-controlled,
// this multiplication can overflow and produce a tiny allocation
// while the subsequent write fills a much larger buffer.
size_t count = get_user_count(); // e.g., 0x40000001
size_t element_size = sizeof(Record); // e.g., 8
size_t total = count * element_size; // OVERFLOW → tiny total
char* buf = (char*)malloc(total); // Tiny allocation!
// ... fill with count * element_size bytes → heap overflow
#include "SafeInt.hpp"
#include <stdlib.h>
struct Record { int id; double value; };
char* safe_allocate(size_t count) {
try {
SafeInt<size_t> safe_count = count;
SafeInt<size_t> safe_size = sizeof(Record);
// If count * sizeof(Record) overflows size_t → exception
size_t total = (size_t)(safe_count * safe_size);
return (char*)malloc(total);
}
catch (const SafeIntException&) {
// count is so large that the allocation would overflow
return nullptr;
}
}
Custom Error Handler
Instead of exceptions, you can provide a custom error handler policy as the second template parameter:
#include "SafeInt.hpp"
#include <cstdio>
#include <cstdlib>
// Custom error handler: logs and terminates instead of throwing
class MyErrorHandler {
public:
static void SafeIntOnOverflow() {
fprintf(stderr, "FATAL: SafeInt overflow detected — terminating\n");
abort();
}
static void SafeIntOnDivZero() {
fprintf(stderr, "FATAL: SafeInt division by zero — terminating\n");
abort();
}
};
int main() {
// Use MyErrorHandler as the error policy
SafeInt<int, MyErrorHandler> a = INT_MAX;
SafeInt<int, MyErrorHandler> b = 1;
// This calls MyErrorHandler::SafeIntOnOverflow() instead of throwing
SafeInt<int, MyErrorHandler> result = a + b;
return 0;
}
Standalone SafeInt Functions
For one-off checked operations without wrapping all variables as SafeInt, use the standalone functions:
#include "SafeInt.hpp"
#include <stdio.h>
int main() {
int a = 1000000, b = 3000;
int result;
// SafeAdd, SafeMultiply, SafeSubtract, SafeDivide
if (SafeMultiply(a, b, result)) {
printf("a * b = %d\n", result);
} else {
printf("Multiplication would overflow!\n");
}
unsigned int ua = 5, ub = 10;
unsigned int udiff;
if (SafeSubtract(ua, ub, udiff)) {
printf("ua - ub = %u\n", udiff);
} else {
printf("Subtraction would underflow!\n"); // 5 - 10 underflows unsigned
}
return 0;
}
Comparison with Compiler /RTC Checks
| Feature | SafeInt | /RTC (Runtime Checks) |
|---|
| Scope | Integer arithmetic overflow | Uninitialized variables, stack frame corruption |
| Overflow detection | ✅ All arithmetic ops | ❌ Does not detect integer overflow |
| Unsigned underflow | ✅ Detected | ❌ Not detected |
| Performance | Small overhead per operation | Debug builds only |
| Production use | ✅ Suitable with performance testing | ❌ Debug builds only (not redistributable) |
| Portability | MSVC, GCC, Clang | MSVC only |
Use /RTC1 during development to catch stack corruption and uninitialized variables, and pair it with SafeInt for arithmetic operations in security-sensitive code paths. The two tools complement each other and address different vulnerability classes.
SafeIntException Reference
// SafeIntException members:
class SafeIntException {
public:
SafeIntError m_code; // Error code indicating the type of overflow
};
// SafeIntError values:
// SafeIntNoError — No error
// SafeIntArithmeticOverflow — Arithmetic overflow
// SafeIntDivideByZero — Division by zero
// Example: inspecting the error code
try {
SafeInt<short> s = 30000;
SafeInt<short> result = s + s; // 60000 overflows short (max 32767)
}
catch (const SafeIntException& ex) {
switch (ex.m_code) {
case SafeIntArithmeticOverflow:
printf("Arithmetic overflow\n");
break;
case SafeIntDivideByZero:
printf("Division by zero\n");
break;
default:
printf("SafeInt error code: %d\n", (int)ex.m_code);
break;
}
}