Document number:P0228R2Project:Programming Language C++Audience:SG-6Author:Robert RameyContact:ramey@rrsd.comDate:2016-02-16A Proposal to Add Safe Integer Types to the Standard
LibraryMotivationArithmetic operations in C++ are NOT guaranteed to yield a correct
mathematical result. This feature is inherited from the early days of C.
The behavior of int, unsigned int and others
were designed to map closely to the underlying hardware. Computer hardware
implements these types as a fixed number of bits. When the result of
arithmetic operations exceeds this number of bits, the result will not be
arithmetically correct. The following example illustrates this
problem.int f(int x, int y){
// this returns an invalid result for some legal values of x and y !
return x + y;
}
Impact On the StandardThis proposal is a pure library extension. It does not require
changes to any standard classes, functions or headers. It might benefit
from relaxing some of the conditions on aggregate types. It has been
implemented in and requires standard C++/14.Design DecisionsThe template class is designed to function as closely as possible as
a drop-in replacement for corresponding built-in integer types."Drop In Replacement for Any Integer Type"The template class is designed to function as closely as
possible as a drop-in replacement for corresponding built-in integer
types. Ideally, one should be able to just substitute safe<T>
for all instances of T in any program and expect it compile and
execute as before with no other changes.Since C++ permits freely mixing signed and unsigned integer
types in expressions, safe versions of these types can also be. This
complicates the implementation of the library to significant
degree."Return No Incorrect Results"Usage of a safe type in a binary expression is guaranteed to
either return an arithmetically correct result or throw a standard
exception."Automatically Inter operate with built-in integer types"The usage of a safe type in binary expression "infects" the
expression by returning another safe type. This is designed to avoid
accidentally losing the safety of the expression."Uses <limits> instead of type traits"Implementation of a library such as this necessarily keeps track
of the types of data objects. The most common way to do this is using
type_traits such as std::is_integral,
std::is_unsigned, std::is_arithmetic, etc.
This doesn't work very well for a few reasons:These are defined by the standard to apply only to
built-in types. Specializing these traits for new types such as
safe<int> would conflict with the standard.We are allowed to create specialization of
std::numeric_limits for our own types - including safe<T>.
So this works well for us.safe<T> might be implemented in such as way that it
would work for unforeseen integer-like types such as "money".
Numeric limits has more complete information about these types
which might make it easier to extend the library."Performance"Performance will depend on the implementation and subject to the
constraints above. This design will permit the usage of template
meta-programming to eliminate runtime performance penalties in some
cases. In the following example, there is no runtime penalty required
to guarantee that incorrect results will never be generated.#include <cstdint>
#include <safe>
using namespace std;
int f(safe<int8_t> i){
// C++ promotion rules make overflow on multiplication impossible!
// cannot fail on return
// zero performance penalty
return i * i;
}
int8_t f(safe<int8_t> i){
// C++ promotion rules make overflow on multiplication impossible!
// but result could be truncated on return
// so result must be checked at runtime incurring a runtime penalty
return i * i; // cannot overflow on multiplication,
}Some processors have the ability to detect erroneous results but
the C++ language doesn't include the ability to exploit these
features. Implementor's of this library will have the option to
exploit these features to diminish or eliminate runtime costs.If all else fails and the runtime cost is deemed too large for
the program to bear, users will have the option of creating their own
aliases for the types the program uses and assign them according to
the whether they are building a "Debug" or "Release" version. This is
not ideal, but would still be preferable to the current approach which
generally consists of ignoring the possibility that C++ numeric
operations may produce arithmetically incorrect results."No Extra Parameters"An alternative to this proposal would be a policy based design
which would permit users to select or define actions to be taken in
the case of errors. This is quite possible and likely useful. However,
the simplicity usage of the current proposal is an important feature.
So I decided not to include it."No other safe types"Other ideas come to mind such as safe<Min,
Max>, safe_literal<Value>, and others. I
excluded these in the spirit of following the controlling purpose of
making a "drop in replacement". Once one included these types into a
program, they change the semantics of the program so that it's not
really C++ any more. There is a place for these ideas, (see below),
but I don't think the standard library is that place.Existing ImplementationsThis proposal is a simpler version / subset of the Safe Numerics
library in development by Robert Ramey on the Boost
Library Incubator. It is compatible with this proposal but it also
includes:Policy classes for error handlingPolicy classes for type promotion. These permit substitution
of C++ standard type promotion rules with other ones which can reduce
or eliminate the need for runtime error checking code.Other safe types such as safe_integer_range<Min,
Max>.Complete documentation including internal operationWithout comment, here are implementations of libraries which are in
some way similar to this proposal:Robert Leahy,
Safe integer utilities for C++11David LeBlanc,
SafeIntDavid Stone, Bounded
IntegerTechnical SpecificationsType RequirementsTypessafe<T>DescriptionA safe<T> can be used anywhere a type T can
be used. Any expression which uses this type is guaranteed to return
an arithmetically correct value or trap in some way.NotationSymbolDescriptionTUnderlying type from which a safe type is being
derivedTemplate ParametersParameterType RequirementsDescriptionTIntegerThe underlying type. Currently only integer types
supportedSee examples below.Model ofIntegerSafeNumericValid ExpressionsImplements all expressions defined by the SafeNumeric type
requirements.safe<T> is meant to be a "drop-in"
replacement of the intrinsic integer types.The type of an expression of type safe<T> op safe<U>
will be safe<R> where R would be the same as the type of the
expression T op U.That is, expressions involving these types will be
evaluated into result types which reflect the standard rules for
evaluation of C++ expressions. Should it occur that such evaluation
cannot return a correct result, an std::exception will be
thrown.Header#include
<safe>Example of usesafe<T> is meant to be a "drop-in"
replacement of the intrinsic integer types. That is, expressions
involving these types will be evaluated into result types which
reflect the standard rules for evaluation of C++ expressions. Should
it occur that such evaluation cannot return a correct result, an
exception will be thrown.The following program will throw an exception
and emit a error message at runtime if any of several events result in
an incorrect arithmetic type. Behavior of this program could vary
according to the machine architecture in question.#include <exception>
#include <iostream>
#include <safe>
void f(){
using namespace std;
safe<int> j;
try {
safe<int> i;
cin >> i; // could throw overflow !
j = i * i; // could throw overflow
}
catch(std::exception & e){
std::cout << e.what() << endl;
}
std::cout << j;
}AcknowledgementsThis proposal is a simplified version of Safe Numeics library
proposed for Boost. This effort was inspired by David LeBlanc's SafeInt Library
.ReferencesOmer KatzSafeInt
code proposalBoost
Developer's ListKatzPosts of various authors regarding a proposed SafeInt library
for boostDavid LeBlancInteger
Handling with the C++ SafeInt ClassMicrosoft Developer NetworkJanuary 7, 2004LeBlancDavid LeBlancSafeIntCodePlexDec 3, 2014LeBlancJacques-Louis LionsAriane
501 Inquiry Board reportWikisourceJuly 19, 1996LionsDaniel PlakoshSafe
Integer OperationsU.S. Department of
Homeland SecurityMay 10, 2013PlakoshRobert C. SeacordSecure
Coding in C and C++2nd EditionAddison-Wesley ProfessionalApril 12, 2013978-0321822130SeacordRobert C. SeacordINT30-C.
Ensure that operations on unsigned integers do not wrapSoftware Engineering Institute,
Carnegie Mellon UniversityAugust 17, 2014INT30-CRobert C. SeacordINT32-C.
Ensure that operations on signed integers do not result in
overflowSoftware Engineering Institute,
Carnegie Mellon UniversityAugust 17, 2014INT32-C