Document number: P0228R2 Project: Programming Language C++ Audience: SG-6 Author: Robert Ramey Contact: ramey@rrsd.com Date: 2016-02-16 A Proposal to Add Safe Integer Types to the Standard Library
Motivation Arithmetic 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 Standard This 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 Decisions The 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 Implementations This 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 handling Policy 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 operation Without comment, here are implementations of libraries which are in some way similar to this proposal: Robert Leahy, Safe integer utilities for C++11 David LeBlanc, SafeInt David Stone, Bounded Integer
Technical Specifications
Type Requirements
Types
safe<T>
Description A 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.
Notation Symbol Description T Underlying type from which a safe type is being derived
Template Parameters Parameter Type Requirements Description T Integer The underlying type. Currently only integer types supported See examples below.
Model of Integer SafeNumeric
Valid Expressions Implements 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 use safe<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; }
Acknowledgements This proposal is a simplified version of Safe Numeics library proposed for Boost. This effort was inspired by David LeBlanc's SafeInt Library .
References Omer Katz <ulink url="http://www.cert.org/secure-coding/publications/books/secure-coding-c-c-second-edition.cfm?"> <ulink url="http://boost.2283326.n4.nabble.com/SafeInt-code-proposal-td2663669.html">SafeInt code proposal</ulink> </ulink> Boost Developer's List Katz Posts of various authors regarding a proposed SafeInt library for boost David LeBlanc <ulink url="https://msdn.microsoft.com/en-us/library/ms972705.aspx">Integer Handling with the C++ SafeInt Class</ulink> Microsoft Developer Network January 7, 2004 LeBlanc David LeBlanc <ulink url="https://safeint.codeplex.com">SafeInt</ulink> CodePlex Dec 3, 2014 LeBlanc Jacques-Louis Lions <ulink url="https://en.wikisource.org/wiki/Ariane_501_Inquiry_Board_report">Ariane 501 Inquiry Board report</ulink> Wikisource July 19, 1996 Lions Daniel Plakosh <ulink url="https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/312-BSI.html">Safe Integer Operations</ulink> U.S. Department of Homeland Security May 10, 2013 Plakosh Robert C. Seacord <ulink url="http://www.cert.org/secure-coding/publications/books/secure-coding-c-c-second-edition.cfm?">Secure Coding in C and C++</ulink> 2nd Edition Addison-Wesley Professional April 12, 2013 978-0321822130 Seacord Robert C. Seacord <ulink url="https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false">INT30-C. Ensure that operations on unsigned integers do not wrap</ulink> Software Engineering Institute, Carnegie Mellon University August 17, 2014 INT30-C Robert C. Seacord <ulink url="https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow">INT32-C. Ensure that operations on signed integers do not result in overflow</ulink> Software Engineering Institute, Carnegie Mellon University August 17, 2014 INT32-C