From f43dfc7b382aa0bcd8dfdda1675605e8285b5d92 Mon Sep 17 00:00:00 2001 From: Robert Ramey Date: Mon, 8 Jun 2015 15:43:23 -0700 Subject: [PATCH] first version with working policies promotion pollicy exception policy improved documentation --- doc/boostbook/HTML.manifest | 31 ++++ doc/boostbook/exception_policy_concept.xml | 5 +- doc/boostbook/promotion_policy_concept.xml | 2 +- doc/boostbook/safe_introduction.xml | 173 ++++++++++++++++++ doc/html/bibliography.html | 133 ++++++++++++++ doc/html/change_log.html | 13 +- doc/html/concepts.html | 15 +- doc/html/exception_polcy.html | 162 +++++++++++++++++ doc/html/exception_safety.html | 44 +++++ doc/html/functions.html | 18 +- doc/html/index.html | 49 +++-- doc/html/introduction.html | 35 ++-- doc/html/introduction/problem.html | 80 ++++++++ doc/html/introduction/requirements.html | 55 ++++++ doc/html/introduction/scope.html | 49 +++++ doc/html/introduction/solution.html | 70 +++++++ doc/html/introduction/summary.html | 60 ++++++ doc/html/notes.html | 27 ++- doc/html/numeric.html | 71 ++++---- doc/html/pending_issues.html | 60 ++++++ doc/html/promotion_policy.html | 201 +++++++++++++++++++++ doc/html/rationale.html | 187 ++++++++++++++++--- doc/html/safe.html | 125 +++++++++---- doc/html/safe_cast.html | 58 +++--- doc/html/safe_compare.html | 79 ++++---- doc/html/safe_signed_range.html | 135 ++++++++++++-- doc/html/safe_unsigned_range.html | 135 +++++++++++--- doc/html/tutorial.html | 26 ++- doc/html/tutorial/1.html | 40 ++-- doc/html/tutorial/2.html | 34 +++- doc/html/tutorial/3.html | 75 ++++---- doc/html/tutorial/4.html | 110 +++++++++++ doc/html/tutorial/5.html | 87 +++++++++ doc/html/tutorial/6.html | 98 ++++++++++ doc/html/types.html | 19 +- examples/example5.cpp | 40 ++++ examples/example6.cpp | 50 +++++ 37 files changed, 2301 insertions(+), 350 deletions(-) create mode 100644 doc/boostbook/HTML.manifest create mode 100644 doc/boostbook/safe_introduction.xml create mode 100644 doc/html/bibliography.html create mode 100644 doc/html/exception_polcy.html create mode 100644 doc/html/exception_safety.html create mode 100644 doc/html/introduction/problem.html create mode 100644 doc/html/introduction/requirements.html create mode 100644 doc/html/introduction/scope.html create mode 100644 doc/html/introduction/solution.html create mode 100644 doc/html/introduction/summary.html create mode 100644 doc/html/pending_issues.html create mode 100644 doc/html/promotion_policy.html create mode 100644 doc/html/tutorial/4.html create mode 100644 doc/html/tutorial/5.html create mode 100644 doc/html/tutorial/6.html create mode 100644 examples/example5.cpp create mode 100644 examples/example6.cpp diff --git a/doc/boostbook/HTML.manifest b/doc/boostbook/HTML.manifest new file mode 100644 index 0000000..b026159 --- /dev/null +++ b/doc/boostbook/HTML.manifest @@ -0,0 +1,31 @@ +../html/index.html +../html/introduction.html +../html/introduction/problem.html +../html/introduction/solution.html +../html/introduction/summary.html +../html/introduction/requirements.html +../html/introduction/scope.html +../html/tutorial.html +../html/tutorial/1.html +../html/tutorial/2.html +../html/tutorial/3.html +../html/tutorial/4.html +../html/tutorial/5.html +../html/tutorial/6.html +../html/notes.html +../html/concepts.html +../html/numeric.html +../html/promotion_policy.html +../html/exception_polcy.html +../html/types.html +../html/safe.html +../html/safe_unsigned_range.html +../html/safe_signed_range.html +../html/functions.html +../html/safe_cast.html +../html/safe_compare.html +../html/exception_safety.html +../html/rationale.html +../html/pending_issues.html +../html/change_log.html +../html/bibliography.html diff --git a/doc/boostbook/exception_policy_concept.xml b/doc/boostbook/exception_policy_concept.xml index c2f654d..bcc3b31 100644 --- a/doc/boostbook/exception_policy_concept.xml +++ b/doc/boostbook/exception_policy_concept.xml @@ -1,7 +1,7 @@ -
+
ExceptionPolicy<EP>
@@ -139,8 +139,7 @@ Use this policy to trap at compile time any operation which would otherwise trap at runtime. Hence expressions such as i/j will - trap at compile time unless j can be guaranteed to not be zero. - + trap at compile time unless j can be guaranteed to not be zero.
diff --git a/doc/boostbook/promotion_policy_concept.xml b/doc/boostbook/promotion_policy_concept.xml index af9d0b2..6d3daaf 100644 --- a/doc/boostbook/promotion_policy_concept.xml +++ b/doc/boostbook/promotion_policy_concept.xml @@ -1,7 +1,7 @@ -
+
PromotionPolicy<PP>
diff --git a/doc/boostbook/safe_introduction.xml b/doc/boostbook/safe_introduction.xml new file mode 100644 index 0000000..b3844e2 --- /dev/null +++ b/doc/boostbook/safe_introduction.xml @@ -0,0 +1,173 @@ + + +
+ Introduction + +
+ Problem + + 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; +} + + + It is incumbent up the C/C++ programmer to guarantee that this + behavior does not result in incorrect or unexpected operation of the + program. There are no language facilities which do this. They have to be + explicitly addressed in the program code. There are a number of ways to do + this. SeeINT32-C seems to recommend the following + approach. + + int f(int x, int y){ + if (((y > 0) && (x > (INT_MAX - y))) + || ((y < 0) && (x < (INT_MIN - x)))) { + /* Handle error */ + } + return x + y; +} + + + This will indeed trap the error. However, it would be tedious and + laborious for a programmer to do alter his code to do. Altering code in + this way for all arithmetic operations would likely render the code + unreadable and add another source of potential programming errors. This + approach is clearly not functional when the expression is even a little + more complex as is shown in the following example. + + int f(int x, int y, int z){ + // this returns an invalid result for some legal values of x and y ! + return x + y * z; +} + +
+ +
+ Solution + + This library implements special versions of int, unsigned, etc. + which behave exactly like the original ones EXCEPT that the results of + these operations are guaranteed to be either arithmetically correct or + invoke an error. Using this library, the above would be rendered + as: + + #include <boost/safe_numeric/safe_integer.hpp> + +int f(safe<int> x, safe<int> y){ + return x + y; // throw exception if correct result cannot be returned +} + + + The addition expression is checked at runtime or (if possible) + compile time to trap any possible errors resulting from incorrect + arithmetic behavior. This will permit one to write arithmetic expressions + that cannot produce an erroneous result. Instead, one and only one of the + following is guaranteed to occur. + + + + the expression will emit a compilation error. + + + + the expression will invoke a runtime exception. + + + + the expression will yield the correct mathematical + result + + In addition to eliminating undefined behavior from + primitive integer types, we define new data types + safe_signed_range<MIN, MAX> and + safe_unsigned_range<MIN, MAX> which will throw an + exception if an attempt is made to store a result which is outside the + closed range [MIN, MAX]. +
+ +
+ Summary + + Using techniques of C++ including overloading, template + metaprogramming, and others, this library implements special versions of + int, unsigned, etc. named safe<int>, + safe<unsigned int> etc. These behave exactly like the + original ones EXCEPT that expressions involving these types are checked to + guarantee any possible arithmetic errors are trapped at compile time (if + possible) or at runtime. Since these types are meant to be "drop-in" + replacements - they function in all other ways the same as the built-in + types they are meant to replace. So things which are legal - such as + assigning an signed to unsigned value are not trapped at compile time - as + they are legal C/C++ code - but rather checked at runtime to trap the case + where this (legal) operation would lead to an arithmetically incorrect + result. + + Note that the library addresses arithmetical errors generated by + straightforward C/C++ expressions. Some of these arithmetic errors are + defined as conforming to C/C++ standard while others are not. So it's + misleading to characterize this library as addressing undefined behavior + of C/C++ numeric expressions. +
+ +
+ Requirements + + This library is composed entirely of C++ Headers. I requires a + compiler compatible with the C++11 standard. + + The following Boost Libraries must be installed in order to use this + library + + + + mpl + + + + integer + + + + limits + + + + config + + + + concept checking + + + + type traits + + + + integer traits + + +
+ +
+ Scope + + This library currently applies only to built-in integer types. + Analogous issues arise for floating point types but they are not currently + addressed by this version of the library. User or Library defined types + such as arbitrary precision integers can also have this problem. Extension + of this library to these other types is not currently under development + but may be addressed in the future. This is one reason why the library + name is "safe numeric" rather than "safe integer" library. +
+
diff --git a/doc/html/bibliography.html b/doc/html/bibliography.html new file mode 100644 index 0000000..1cbc6f4 --- /dev/null +++ b/doc/html/bibliography.html @@ -0,0 +1,133 @@ + + + +Bibliography + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHome +
+
+

+Bibliography

+
+

Robert C. Seacord. + Secure + Coding in C and C++ + . 2nd Edition. Addison-Wesley Professional. April 12, 2013. 978-0321822130. Seacord

+
+ + +
+

Daniel Plakosh. + Safe + Integer Operations + . + U.S. Department of + Homeland Security + . May 10, 2013. Plakosh

+
+ + + +
+

David LeBlanc. + Integer + Handling with the C++ SafeInt Class + . + Microsoft Developer Network + . January 7, 2004. LeBlanc

+
+
+

David LeBlanc. + SafeInt + . + CodePlex + . Dec 3, 2014. LeBlanc

+
+
+

Omer Katz. + + SafeInt + code proposal + + . + Boost + Developer's List + . Katz

+
+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/html/change_log.html b/doc/html/change_log.html index 6e8a1c5..f31ef42 100644 --- a/doc/html/change_log.html +++ b/doc/html/change_log.html @@ -6,8 +6,8 @@ - - + + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -29,12 +29,15 @@

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/concepts.html b/doc/html/concepts.html index 937c2ff..dae218d 100644 --- a/doc/html/concepts.html +++ b/doc/html/concepts.html @@ -1,7 +1,7 @@ -Concepts +Type Requirements @@ -24,12 +24,19 @@

-Concepts

- +Type Requirements
+ -

diff --git a/doc/html/exception_polcy.html b/doc/html/exception_polcy.html new file mode 100644 index 0000000..cd15b99 --- /dev/null +++ b/doc/html/exception_polcy.html @@ -0,0 +1,162 @@ + + + +ExceptionPolicy<EP> + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+ExceptionPolicy<EP>

+ +
+

+Description

+

The exception policy specifies what is to occur when a safe + operation cannot return a valid arithmetic result. A type is an + ExceptionPolicy if it has functions for handling exceptional events that + occur in the course of safe numeric operations.

+
+
+

+Notation

+
+

Table 9. Notation

+
++++ + + + + + + + + + + +
EPA type that full fills the requirements of an + ExceptionPollicy
messageA const char * which refers to a text message about the + cause of an exception
+
+
+
+
+

+Valid Expressions

+

Any operations which result in integers which cannot be represented + as some Numeric type will throw an exception.

+
+

Table 10. General

+
++++ + + + + + + + + + + + + + + + + + + +
ExpressionReturn Value
EP::overflow_error(const char * + message)void
EP::underflow_error(const char * + message)void
EP::range_error(const char * + message)void
+
+


+
+ +
+

+Models

+

The library header #include + <safe_numerics/include/exception_policy.hpp> contains + a number of pre-made exception policies:

+
    +
  • +

    boost::numeric::ignore_exception

    +

    Emulate the normal C/C++ behavior of permitting overflows, + underflows etc.

    +
  • +
  • +

    boost::numeric::throw_exception

    +

    If an exceptional condition is detected at runtime throw the + exception. Safe types use this exception policy as the default if no + other one is specified.

    +
  • +
  • +

    template<void (*F)(const char *), void (*G)(const char + *), void (*H)(const char *)>

    +

    boost::numeric::no_exception_support

    +

    If you want to specify specific behavior for particular + exception types, use this policy. The most likely situation is where + you don't have exception support and you want to trap "exceptions" by + calling your own special functions.

    +
  • +
  • +

    boost::numeric::trap_exception

    +

    Use this policy to trap at compile time any operation which + would otherwise trap at runtime. Hence expressions such as i/j will + trap at compile time unless j can be guaranteed to not be zero.

    +
  • +
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/exception_safety.html b/doc/html/exception_safety.html new file mode 100644 index 0000000..89beceb --- /dev/null +++ b/doc/html/exception_safety.html @@ -0,0 +1,44 @@ + + + +Exception Safety + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Exception Safety

+

All operations in this library are exception safe and meet the + strong guarantee.

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/functions.html b/doc/html/functions.html index bda9f61..61b224b 100644 --- a/doc/html/functions.html +++ b/doc/html/functions.html @@ -6,8 +6,8 @@ - - + + @@ -20,25 +20,27 @@

-PrevUpHomeNext +PrevUpHomeNext
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/index.html b/doc/html/index.html index 8400a0f..27ba523 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -27,43 +27,62 @@
- +

Last revised: , at

Last revised: $Date


diff --git a/doc/html/introduction.html b/doc/html/introduction.html index 26612bb..6141efc 100644 --- a/doc/html/introduction.html +++ b/doc/html/introduction.html @@ -7,7 +7,7 @@ - + @@ -20,37 +20,30 @@

-PrevUpHomeNext +PrevUpHomeNext

Introduction

-

Arithmetic operations in C++ are NOT guarenteed 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 is undefined - and usually not what the programmer intended. It is incumbent up the C++ - programmer to guarentee that this behavior does not result in incorrect - behavior of the program. This library implements special versions of these - data types which behave exactly like the original ones EXCEPT that the - results of these operations are checked to be sure that an exception will - be thrown anytime an attempt is made to store the result of an undefined - operation.

-

Additionally, we define data types safe_signed_range<MIN, - MAX> and safe_unsigned_range<MIN, MAX> which - will throw an exception if an attempt is made to store a result which is - outside the closed range [MIN, MAX]

+
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/introduction/problem.html b/doc/html/introduction/problem.html new file mode 100644 index 0000000..95f6d9d --- /dev/null +++ b/doc/html/introduction/problem.html @@ -0,0 +1,80 @@ + + + +Problem + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Problem

+

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;
+}
+
+

It is incumbent up the C/C++ programmer to guarantee that this + behavior does not result in incorrect or unexpected operation of the + program. There are no language facilities which do this. They have to be + explicitly addressed in the program code. There are a number of ways to do + this. See[INT32-C] seems to recommend the following + approach.

+
int f(int x, int y){
+  if (((y > 0) && (x > (INT_MAX - y))) 
+  || ((y < 0) && (x < (INT_MIN - x)))) {
+    /* Handle error */
+  }
+  return x + y;
+}
+
+

This will indeed trap the error. However, it would be tedious and + laborious for a programmer to do alter his code to do. Altering code in + this way for all arithmetic operations would likely render the code + unreadable and add another source of potential programming errors. This + approach is clearly not functional when the expression is even a little + more complex as is shown in the following example.

+
int f(int x, int y, int z){
+    // this returns an invalid result for some legal values of x and y !
+    return x + y * z;
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/introduction/requirements.html b/doc/html/introduction/requirements.html new file mode 100644 index 0000000..2039b4e --- /dev/null +++ b/doc/html/introduction/requirements.html @@ -0,0 +1,55 @@ + + + +Requirements + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Requirements

+

This library is composed entirely of C++ Headers. I requires a + compiler compatible with the C++11 standard.

+

The following Boost Libraries must be installed in order to use this + library

+
    +
  • mpl

  • +
  • integer

  • +
  • limits

  • +
  • config

  • +
  • concept checking

  • +
  • type traits

  • +
  • integer traits

  • +
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/introduction/scope.html b/doc/html/introduction/scope.html new file mode 100644 index 0000000..fcf900b --- /dev/null +++ b/doc/html/introduction/scope.html @@ -0,0 +1,49 @@ + + + +Scope + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Scope

+

This library currently applies only to built-in integer types. + Analogous issues arise for floating point types but they are not currently + addressed by this version of the library. User or Library defined types + such as arbitrary precision integers can also have this problem. Extension + of this library to these other types is not currently under development + but may be addressed in the future. This is one reason why the library + name is "safe numeric" rather than "safe integer" library.

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/introduction/solution.html b/doc/html/introduction/solution.html new file mode 100644 index 0000000..ba40a88 --- /dev/null +++ b/doc/html/introduction/solution.html @@ -0,0 +1,70 @@ + + + +Solution + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Solution

+

This library implements special versions of int, unsigned, etc. + which behave exactly like the original ones EXCEPT that the results of + these operations are guaranteed to be either arithmetically correct or + invoke an error. Using this library, the above would be rendered + as:

+
#include <boost/safe_numeric/safe_integer.hpp>
+
+int f(safe<int> x, safe<int> y){
+  return x + y; // throw exception if correct result cannot be returned
+}
+
+

The addition expression is checked at runtime or (if possible) + compile time to trap any possible errors resulting from incorrect + arithmetic behavior. This will permit one to write arithmetic expressions + that cannot produce an erroneous result. Instead, one and only one of the + following is guaranteed to occur.

+
    +
  • the expression will emit a compilation error.

  • +
  • the expression will invoke a runtime exception.

  • +
  • the expression will yield the correct mathematical + result

  • +
+

In addition to eliminating undefined behavior from + primitive integer types, we define new data types + safe_signed_range<MIN, MAX> and + safe_unsigned_range<MIN, MAX> which will throw an + exception if an attempt is made to store a result which is outside the + closed range [MIN, MAX].

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/introduction/summary.html b/doc/html/introduction/summary.html new file mode 100644 index 0000000..90e7c15 --- /dev/null +++ b/doc/html/introduction/summary.html @@ -0,0 +1,60 @@ + + + +Summary + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Summary

+

Using techniques of C++ including overloading, template + metaprogramming, and others, this library implements special versions of + int, unsigned, etc. named safe<int>, + safe<unsigned int> etc. These behave exactly like the + original ones EXCEPT that expressions involving these types are checked to + guarantee any possible arithmetic errors are trapped at compile time (if + possible) or at runtime. Since these types are meant to be "drop-in" + replacements - they function in all other ways the same as the built-in + types they are meant to replace. So things which are legal - such as + assigning an signed to unsigned value are not trapped at compile time - as + they are legal C/C++ code - but rather checked at runtime to trap the case + where this (legal) operation would lead to an arithmetically incorrect + result.

+

Note that the library addresses arithmetical errors generated by + straightforward C/C++ expressions. Some of these arithmetic errors are + defined as conforming to C/C++ standard while others are not. So it's + misleading to characterize this library as addressing undefined behavior + of C/C++ numeric expressions.

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/notes.html b/doc/html/notes.html index 1c7dc9c..f79cb62 100644 --- a/doc/html/notes.html +++ b/doc/html/notes.html @@ -6,8 +6,8 @@ - - + + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -32,19 +32,15 @@ tests for my embedded systems projects on my PC. Still, I had a few issues.

    -
  • I was a lot of code in one header - 6400 lines. Very unwieldy to - understand and modify.

  • +
  • It was a lot of code in one header - 6400 lines. Very unwieldy + to understand, modify and maintain.

  • I couldn't find separate documentation other than that in the header file.

  • -
  • I didn't use Boost +

  • It didn't use Boost conventions for naming.

  • -
  • I required porting to different compilers.

  • +
  • It required porting to different compilers.

  • It had a very long license associated with it.

  • -
  • The package I downloaded didn't have a test suite

  • -
  • I believe the original SafeInt - library is not easily found. MSVC 10 has this built in so I seems that - they've decided to make it less attractive to use on other - systems.

  • +
  • I could find not test suite for the library.

This version addresses these issues. It exploits Boost facilities such as template metaprogramming to reduce the number of lines of source code to @@ -55,12 +51,15 @@

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/numeric.html b/doc/html/numeric.html index 12276e8..b0a3c2a 100644 --- a/doc/html/numeric.html +++ b/doc/html/numeric.html @@ -5,9 +5,9 @@ - - - + + + @@ -20,22 +20,22 @@

-PrevUpHomeNext +PrevUpHomeNext

A type is Numeric if it has the properties of a number.

More specifically, a type T is Numeric if there exists specialization of std::numeric_limits<T>. See the @@ -43,16 +43,16 @@ library includes such specializations for all the primitive numeric types. Note that this concept is distinct from the C++ standard library type traits is_integral and is_arithmetic. These - latter fullfill the requirement of the concept Numeric. But there are - types T which fullfill this concept for which - is_arithmetic<T>::value == false. For example see + latter fulfill the requirement of the concept Numeric. But there are types + T which fulfill this concept for which is_arithmetic<T>::value + == false. For example see safe_signed_integer<int>.

-Notation

+Notation
-

Table 1. Notation

+

Table 1. Notation

@@ -74,9 +74,9 @@

-Associated Types

+Associated Types
-

Table 2. Associated Types

+

Table 2. Associated Types

@@ -85,7 +85,7 @@ @@ -95,13 +95,13 @@

-Valid Expressions

+Valid Expressions

In addition to the expressions defined in Assignable the following expressions must be valid.

Any operations which result in integers which cannot be represented as some Numeric type will throw an exception.

-

Table 3. General

+

Table 3. General

std::numeric_limits<T> The numeric_limits class template provides a C++ program - with information about various properties of the implementation’s + with information about various properties of the implementation's representation of the arithmetic types. See C++ standard 18.3.2.2.
@@ -131,7 +131,7 @@


-

Table 4. Unary Operators

+

Table 4. Unary Operators

@@ -167,12 +167,12 @@ - + - + @@ -183,7 +183,7 @@
--t Tpredecrementpre decrement
++t Tpreincrementpre increment
~

-

Table 5. Binary Operators

+

Table 5. Binary Operators

@@ -199,12 +199,12 @@ - + - + @@ -229,7 +229,7 @@ - + @@ -249,7 +249,8 @@ - + @@ -339,25 +340,29 @@

-Header

+Header

#include <safe_numerics/include/concepts/numeric.hpp>

-Models

+Models

int, safe_signed_integer<int>, safe_signed_range<int>, etc.

+

The definition of this concept

t - u VInvert signsubtract u from t
t + u Vunary plus - a no opadd u to t
t * u
t >> u Tshift t right by ubitsshift t right by u bits
t < u
t >= u booltrue if t greathan or equal to u, false otherwisetrue if t greater than or equal to u, false + otherwise
t == u
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/pending_issues.html b/doc/html/pending_issues.html new file mode 100644 index 0000000..6d26c66 --- /dev/null +++ b/doc/html/pending_issues.html @@ -0,0 +1,60 @@ + + + +Pending Issues + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Pending Issues

+

The library is under development. There are a number of issues still + pending.

+
    +
  • The library is currently limited to integers.

  • +
  • Conversions to safe integer types from floating point types is + not checked.

  • +
  • Stream input of safe integer types is not checked. Note that + standard library stream conversion functions such as + strtoi etc. DO check for valid input and throw the + exception std::out_of_range if the string cannot be + converted to the specified integer type. In other words, + strtoi aready contains the exact functionality that + safe<int> provides.

  • +
  • There is currently no convenient way to override the overflow + function.

  • +
  • Expressions with safe integer types don't return safe integer + types.

  • +
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/promotion_policy.html b/doc/html/promotion_policy.html new file mode 100644 index 0000000..ed7d1e5 --- /dev/null +++ b/doc/html/promotion_policy.html @@ -0,0 +1,201 @@ + + + +PromotionPolicy<PP> + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+PromotionPolicy<PP>

+ +
+

+Description

+

In C++, arithmetic operations result in types which may or may not + be the same as the constituent types. For example, A promotion policy + determines the type of the result of an arithmetic operation. For example, + in the following code

+
int x;
+char y;
+auto z = x + y
+

the type of z will be an + int. This is a consequence for the standard rules for type + promotion for C/C++ arithmetic. A key feature of library permits one to + specify his own type promotion rules via a PromotionPolicy class.

+
+
+

+Notation

+
+

Table 6. Notation

+
++++ + + + + + + + + + + + + + + +
PPA type that full fills the requirements of a + PromotionPollicy
T, U, VA type that is a model of the Numeric concept
t, u, vAn object of type modeling Numeric
+
+
+
+
+

+Associated Types

+
+

Table 7. Associated Types

+
++++ + + + + +
EPA type that full fills the requirements of an + ExceptionPollicy
+
+
+
+
+

+Valid Expressions

+

Any operations which result in integers which cannot be represented + as some Numeric type will throw an exception.

+
+

Table 8. Valid Expressions

+
++++ + + + + + + + + + + + + + + +
ExpressionReturn Value
PP::addition_result<T, U, PP, + EP>::typeunspecified Numeric type
PP::subtraction_result<T, U, PP, + EP>::typeunspecified Numeric type
+
+


+
+ +
+

+Models

+

The library contains a number of pre-made promotion policies:

+
    +
  • +

    boost::numeric::native

    +

    Use the normal C/C++ expression type promotion rules. +

    +
    int x;
    +char y;
    +auto z = x + y; // could result in overflow
    +safe<int> sx;
    +auto sz = sx + y; // includes code which traps overflows at runtime
    +

    The type of sz will be safe< type of z >.

    +

    This policy is found in the header file #include + <safe_numerics/include/native.hpp>

    +
  • +
  • +

    boost::numeric::automatic

    +

    Use optimizing expression type promotion rules. These rules + replace the normal C/C++ type promotion rules with other rules which + are designed to result in more efficient computations. Expression + types are promoted to the smallest type which can be guaranteed to + hold the result without overflow. If there is no such type, the result + will be checked for overflow. Consider the following + example:

    +
    int x;
    +char y;
    +auto z = x + y; // could result in overflow
    +safe<int> sx;
    +auto sz = sx + y; // promotes expression type to a safe<long int> which requires no result checking
    +is guaranteed not to overflow.
    +
    +safe_unsigned_range<1, 4> a;
    +safe_unsigned_range<2, 4> b;
    +auto c = a + b; // c will be of type safe_unsigned_range<3, 8> and cannot overflow
    +

    Type sz will be a SafeNumeric type which is guaranteed to hold + he result of x + y. In this case that will be a long int (or perhaps a + long ong) depending upon the compiler and machine architecture. In + this case, there will be no need for any special checking on the + result and there can be no overflow.

    +

    Type of c will be a signed caracter as that type can be + guarenteed to hold the sum so no overflow checking is done.

    +

    This policy is found in the header file #include + <safe_numerics/include/automatic.hpp>

    +
  • +
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/rationale.html b/doc/html/rationale.html index dc609f6..f6f6c7b 100644 --- a/doc/html/rationale.html +++ b/doc/html/rationale.html @@ -6,8 +6,8 @@ - - + + @@ -20,21 +20,43 @@

-PrevUpHomeNext +PrevUpHomeNext

Rationale

-
-
1. Why does a binary operation on two - safe<int> values not necessarily return another +
+
1. Why does a binary operation on two + safe<int> values not return another safe type ?
-
2. Why is there no policy driven design for handling - overflows +
2. Why is there no policy driven design for handling + overflows?
-
3. Why is Boost.Convert not used. +
3. Why is Boost.Convert not used. +
+
4. Why is the library named "safe ..." rather than something like + "checked ..." ? +
+
5. Given that the library is called "numerics" why is floating + point arithmetic not addressed? +
+
6. Isn't putting a defensive check just before any potential UB, + is often considered a bad practice? +
+
7. Why are safe_compare and safe_cast included in the library? + The don't really fit with the "drop-in" replacement idea for + built-in types. +
+
8. It looks like it presumes two's complement arithmetic at the + hardware level. So this library is not portable - correct? What + about other hardware architectures? +
+
9. Why do you specialize numeric_limits for "safe" types? Do you + need it? +
+
10.
@@ -43,18 +65,18 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-

1.

+

1.

Why does a binary operation on two - safe<int> values not necessarily return another + safe<int> values not return another safe type ?

-

There are a number of

+

There are a number of reasons:

    -
  • it was hard to implement.

  • +
  • it was too hard to implement.

  • it doesn't really seem necessary. We always do SOMETHING with result of the operation. This will result in an assignment or a conversion to some other type where the result will be @@ -64,27 +86,131 @@

-

2.

-
-

Why is there no policy driven design for handling - overflows

-

The question was - to which type does one apply it to? - Consider the following example:

-
safe<int, overflow_policy_1> t1 = 2;
-safe<int, overflow_policy_2> t2 = 4;
-unsigned int x = t1 - t2; // which policy should be invoked?
+

2.

Why is there no policy driven design for handling + overflows?

This is planned for a future version of the library. However, + attempts to implement this idea have so far failed as it turns out + to more technically challenging than one would think. Rather than + wait for a future event that might never happen, it was decided to + release the library without this feature.

-

3.

+

3.

Why is Boost.Convert not used.

I couldn't figure out how to use it from the + documentation.

-

Why is Boost.Convert not used.

-

I couldn't figure out how to use it from the - documentation.

+

4.

Why is the library named "safe ..." rather than something like + "checked ..." ?

I used "safe" in large part this is what has been used by + other similar libraries. Maybe a better word might have been + "correct" but that would raise similar concerns. I'm not inclined to + change this. I've tried to make it clear in the documentation what + the problem that the library addressed is

+

5.

+

Given that the library is called "numerics" why is floating + point arithmetic not addressed?

Actually, I believe that this can/should be applied to any + type T which satisfies the type requirement "Numeric" type as + defined in the documentation. So there should be specializations + safe<float> et. al. and eventually safe<fixed_decimal> + etc. But the current version of the library only addresses integer + types. Hopefully the library will evolve to match the promise + implied by it's name.

+

6.

+

Isn't putting a defensive check just before any potential UB, + is often considered a bad practice?

By whom? Is leaving code which can produce incorrect results + better? Note that the documentation contains references to various + sources which recommend exactly this approach to mitigate the + problems created by this C/C++ behavior.

+

7.

+

Why are safe_compare and safe_cast included in the library? + The don't really fit with the "drop-in" replacement idea for + built-in types.

They are part of the implementation of the library. I thought + they would be useful outside the formal context of the library so I + make access to them public.

+

8.

+

It looks like it presumes two's complement arithmetic at the + hardware level. So this library is not portable - correct? What + about other hardware architectures?

Correct. Almost all hardware in current use two's complement + arithmetic. This library works all and only on all such machines. + For example, if one were to implement 48 bit integers with two's + complement arithmetic, the save .. versions could be used without + change. To support hardware which does not use two's complement + arithmetic, at least part of the library would have to be + re-implemented.

+

9.

+

Why do you specialize numeric_limits for "safe" types? Do you + need it?

safe<T> behaves like a "number" just as int does. It has + max, min, etc Any code which uses numeric limits to test a type T + should works with safe<T>. safe<T> is a drop-in + replacement for T so it has to implement all the operations.

+

10.

+

@@ -92,12 +218,15 @@ unsigned int x = t1 - t2; // which policy should be invoked?
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/safe.html b/doc/html/safe.html index edafc28..31afc8d 100644 --- a/doc/html/safe.html +++ b/doc/html/safe.html @@ -6,8 +6,8 @@ - - + + @@ -20,32 +20,63 @@

-PrevUpHomeNext +PrevUpHomeNext

A safe<T> can be used anywhere a type T is used. When T is used in operation which overflows, a exception is thrown

-Template Parameters

-

+Notation
+
++++ + + + + + + + + + + + + + + + + + + + + + + +
SymbolDescription
T, U, VTypes which model the Numeric concept
t, u, vobjects of types T
stobject of type safe<T>
suobject of type safe<U>
+ +
+

+Template Parameters

@@ -59,58 +90,71 @@ - - + +
TNumeric

The underlying integer type

boost::is_integer<T>::value + == true

The underlying intrinsic integer type

-Model of

+Model of

Numeric

-Derived From

-

safe_signed_range<T> - (if std::numeric_limits<T>::is_signed == ftrue)

-

safe_unsigned_range<T> - (if std::numeric_limits<T>::is_signed == ftrue)

-
-
-

-Notation

+Valid Expressions
+ - + + - - + + + - - + + + + + + + + + + + + +
SymbolExpressionResult Type Description
TA type that models the Numeric conceptst op usafe<typeof(t op + u)>

op is any valid binary operator for type + T

tAn object of type T -t op susafe<typeof(t op + u)>

op is any valid binary operator for type + T

st op susafe<typeof(t op + u)>

op is any valid binary operator for type + T

st(t)safe<T>

construct a instance of safe<T> from + t

-Header

+Header

#include <boost/safe_numerics/safe_integer.hpp>

-Example of use

+Example of use

The following program will emit an error message on a machine where int is only 16 bits but run without problem on a machine where int is 32 bits.

@@ -131,25 +175,28 @@ void f(){

-Notes

+Notes

Footnotes (if any) that are referred to by other parts of the page.

-See Also

+See Also

Footnotes (if any) that are referred to by other parts of the page.

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/safe_cast.html b/doc/html/safe_cast.html index 741724b..0c3bbc5 100644 --- a/doc/html/safe_cast.html +++ b/doc/html/safe_cast.html @@ -1,13 +1,13 @@ -safe_cast +safe_cast<T, U> - + @@ -24,32 +24,33 @@

-safe_cast

+safe_cast<T, U>

-Synopsis

+Synopsis
template<class T, class U>
 T safe_cast(const U & u);

-Description

-

Converts one Numeric type - to another. Throws an std::out_of_range exception if such a - conversion is not possible without changing the value.

+Description
+

Converts one Numeric + type to another. Throws an std::out_of_range exception if + such a conversion is not possible without changing the value. This + function is part of the implementation of the safe numerics library. It's + been made publicly because it might be useful in related contexts.

-Type requirements

+Type requirements
@@ -62,39 +63,31 @@ T safe_cast(const U & u); - + - +
TNumericNumeric
U NumericNumeric

-Preconditions

-

The value of u can be represented by the type T. If +Preconditions

+

The value of u must be representable by the type T. If this is not true, an std::out_of_range exception will be thrown.

-Complexity

-

[Example:]

-

O(N log(N)) comparisons (both average and worst-case), where N is - last - first. [2]

-
-
-

-Header

+Header

#include <boost/numeric/safe_cast.hpp>

-Example of use

-

[A code fragment that illustrates how to use the function.]

+Example of use
#include <boost/numeric/safe_cast.hpp> 
 #include <boost/numeric/safe_integer.hpp> 
 
@@ -112,7 +105,10 @@ void f(){
 
 
-

diff --git a/doc/html/safe_compare.html b/doc/html/safe_compare.html index 78f8285..4f6e5af 100644 --- a/doc/html/safe_compare.html +++ b/doc/html/safe_compare.html @@ -1,13 +1,13 @@ -safe_compare +safe_compare<T, U> - - + + @@ -20,44 +20,55 @@

-PrevUpHomeNext +PrevUpHomeNext

-safe_compare

+safe_compare<T, U>

-Synopsis

-

safe_compare is really two functions:.

+Synopsis
+

safe_compare is several functions:.

template<class T, class U>
 bool safe_compare::less_than(const T & lhs, const U & rhs);
 
 template<class T, class U>
-bool safe_compare::greater_than(const T & lhs, const U & rhs);
+bool safe_compare::less_than_equal(const T & lhs, const U & rhs); + +template<class T, class U> +bool safe_compare::greater_than(const T & lhs, const U & rhs); + +template<class T, class U> +bool safe_compare::greater_than_equal(const T & lhs, const U & rhs); + +template<class T, class U> +bool safe_compare::equal(const T & lhs, const U & rhs); + +template<class T, class U> +bool safe_compare::not_equal(const T & lhs, const U & rhs);

-Description

+Description

With normal comparison operators, comparison of unsigned types to signed types will be done by converting the unsigned type to a signed type before comparing. Unfortunately this is not always possible. Most C++ compilers will emit an warning message when this is possible but won't - check that an error is made in the conversion. This function guarentees a - correct result regardless of the types of the arguments.

+ check that an error is made in the conversion. This function guarantees a + correct result regardless of the types of the arguments. It's used in the + implementation of the safe numerics library. It has been made publicly + accessible in because it might be useful in other contexts.

-Type requirements

-

[This section lists the requirements that must be satisfied by the - function's template parameters. If the function has no template - parameters, this section can be skipped. Example:]

+Type requirements
@@ -81,35 +92,41 @@ bool safe_compare::greater_than(const T & lhs, const U & rhs);

-Header

-

[A link to the source code where the function header is - defined.]

+Header

#include <boost/numeric/safe_compare.hpp>

-Example of use

+Example of use
#include <boost/numeric/safe_compare.hpp>
 
 void f(){
-    int i = -1;
-    unsigned char i = 0x129;
+    unsigned char i = 129;
     unsigned int j = 1;
-    bool result;
-    result = j < i; // incorrect result
-    result = safe_compare::less_than(j < i); // correct result
+    assert(j < i); // program traps because expression is false. But this is a surprise because 1 < 129
+    assert( safe_compare::less_than(j,i)); // expression is true as we would expect
+}
+
+// safe_compare is used to implement comparison operators for safe types.  So we can do this:
+void g(){
+    safe<unsigned char> int i = 0x129;
+    safe<int> j = 1;
+    assert(j < i); // program works as expected
 }
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/safe_signed_range.html b/doc/html/safe_signed_range.html index 38d155e..239b058 100644 --- a/doc/html/safe_signed_range.html +++ b/doc/html/safe_signed_range.html @@ -1,13 +1,13 @@ -safe_signed_range<MIN, MAX> +safe_signed_range<boost::intmax_t MIN, boost::intmax_t MAX> - - + + @@ -20,29 +20,68 @@

-PrevUpHomeNext +PrevUpHomeNext

-safe_signed_range<MIN, MAX>

+safe_signed_range<boost::intmax_t MIN, boost::intmax_t + MAX>

-Description

+Description

This type holds a integer in the range [MIN, MAX]. It will throw a std::out_of_range exception for operation which would result in assigning an integer value outside of this range.

-Template Parameters

+Notation
+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
SymbolDescription
T, U, VTypes which model the Numeric concept
t, u, vobjects of types T
ssrobject of type safe_signed_range
ssr(t)some safe range with value t
Ssome safe type
+ +
+

+Template Parameters

@@ -75,18 +114,66 @@

-Model of

+Model of

Numeric

+

The usage of this type in an arithmetic expression will result in + another type fulfilling the Numeric concept.

+

Operations on safe_signed_range will result in the same

-Header

+Valid Expressions
+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExpressionResult TypeDescription
ssr op uS(ssr(t op + u))

op is any valid binary operator for type + T

t op suS(ssr(t op + u))

op is any valid binary operator for type + T

ssr op suS(ssr(t op + u))

op is any valid binary operator for type + T

safe_signed_range(MIN, MAX)safe<T>

construct a instance of safe<T> from + t

+
+

-Example of use

+Example of use
#include <safe/numeric/safe_range.hpp>
 
 void f(){
@@ -94,22 +181,32 @@ void f(){
     i = 0; // error
     i = 9; // ok
     i *= 9; // throws overflow exception
+
+    std::int8_t j = 4;
+    auto k = i + j;
+        // since i can vary between 7 and 24 and j can vary between 0 and 255
+        // the smallest unsigned integer which can hold the result std::int16_t
+        // j will be of type std::int16_t 
 }

-See Also

+See Also

std::out_of_range

+

safe_unsigned_range

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/safe_unsigned_range.html b/doc/html/safe_unsigned_range.html index 4c39116..f0560ab 100644 --- a/doc/html/safe_unsigned_range.html +++ b/doc/html/safe_unsigned_range.html @@ -1,13 +1,13 @@ -safe_unsigned_range<MIN, MAX> +safe_unsigned_range<boost::uintmax_t MIN, boost::uintmax_t MAX> - - + + @@ -20,29 +20,60 @@

-PrevUpHomeNext +PrevUpHomeNext

-safe_unsigned_range<MIN, MAX>

+safe_unsigned_range<boost::uintmax_t MIN, boost::uintmax_t + MAX>

-Description

+Description

This type holds a integer in the range [MIN, MAX]. It will throw a std::out_of_range exception for any operation which would result in assigning an integer value outside of this range.

-Template Parameters

+Notation
+
++++ + + + + + + + + + + + + + + + + + + +
SymbolDescription
T, U, VTypes which model the Numeric concept
t, u, vobjects of types T
surobject of type safe_unsigned_range
+ +
+

+Template Parameters

@@ -57,7 +88,7 @@ - + @@ -67,26 +98,75 @@ - - + +
MINmust be a positive integer literalmust be a non-negative integer literal The minimum integer value that this type may hold
MIN < MAX MIN <= MAX 

-Model of

+Model of

Numeric

+

The usage of this type in an arithmetic expression with another + unsigned type will result in another unsigned type fulfilling the Numeric concept. This will be the + smallest unsigned integer type of sufficient size to hold the result of + the operation.

-Header

+Valid Expressions
+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExpressionResult TypeDescription
st op utypeof(t op + u)

op is any valid binary operator for type + T

t op sutypeof(t op + u)

op is any valid binary operator for type + T

st op sutypeof(t op + u)

op is any valid binary operator for type + T

st(t)safe<T>

construct a instance of safe<T> from + t

+ +

-Example of use

+Example of use
#include <safe/numeric/safe_range.hpp>
 
 void f(){
@@ -95,22 +175,33 @@ void f(){
     i = 9;  // ok
     i *= 9; // throws out_of_range exception
     i = -1; // throws out_of_range exception
+
+    std::uint8_t j = 4;
+    auto k = i + j;
+        // since i can vary between 7 and 24 and j can vary between 0 and 255
+        // the smallest unsigned integer which can hold the result std::uint16_t
+        // j will be of type std::uint16_t 
+    
 }

-See Also

+See Also

std::out_of_range

+

safe_signed_range

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/tutorial.html b/doc/html/tutorial.html index d69f5bf..6babc56 100644 --- a/doc/html/tutorial.html +++ b/doc/html/tutorial.html @@ -1,13 +1,13 @@ -Tutorial +Tutorial and Motivating Examples - - + + @@ -20,25 +20,31 @@

-PrevUpHomeNext +PrevUpHomeNext

-Tutorial

+Tutorial and Motivating Examples
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/tutorial/1.html b/doc/html/tutorial/1.html index 16a9d2c..dc618c8 100644 --- a/doc/html/tutorial/1.html +++ b/doc/html/tutorial/1.html @@ -1,13 +1,13 @@ -Problem:arithmetic operations can yield in correct results. +Arithmetic operations can yield incorrect results. - - - + + + @@ -24,20 +24,33 @@

-Problem:arithmetic operations can yield in correct results.

+Arithmetic operations can yield incorrect results.

When some operation results in a result which exceeds the capacity of a data variable to hold it, the result is undefined. This is called "overflow". Since word size can differ between machines, code which produces correct results in one set of circumstances may fail when re-compiled on a machine with different hardware. When this occurs, Most C++ compilers will continue to execute with no indication that the results - are wrong. It is the programmer's responsabiity to ensure such undefined + are wrong. It is the programmer's responsibility to ensure such undefined behavior is avoided.

This program demonstrates this problem. The solution is to replace instances of char type with safe<char> type.

-
void example1(){
-    // problem: undetected erroneous expression evaluation
+
#include <cassert>
+#include <stdexcept>
+#include <iostream>
+
+#include "../include/safe_integer.hpp"
+//#include "../include/safe_compare.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    std::cout << "example 1:";
+    std::cout << "undetected erroneous expression evaluation" << std::endl;
+    std::cout << "Not using safe numerics" << std::endl;
     try{
         char x = 127;
         char y = 2;
@@ -49,13 +62,14 @@
         // but assert fails to detect it since C++ implicitly
         // converts variables to int before evaluating he expression!
         assert(z != x + y);
-        std::cout << static_cast<int>(z) << " != " << x + y;
+        std::cout << static_cast<int>(z) << " != " << x + y << std::endl;
         detected_msg(false);
     }
     catch(...){
         assert(false); // never arrive here
     }
     // solution: replace char with safe<char>
+    std::cout << "Using safe numerics" << std::endl;
     try{
         using namespace boost::numeric;
         safe<char> x = 127;
@@ -67,15 +81,19 @@
     }
     catch(std::range_error & e){
         // which can catch here
-        std::cout << e.what();
+        std::cout << e.what() << std::endl;
         detected_msg(true);
     }
+    return 0;
 }
 
-

diff --git a/doc/html/tutorial/2.html b/doc/html/tutorial/2.html index 3144e7c..0ac4559 100644 --- a/doc/html/tutorial/2.html +++ b/doc/html/tutorial/2.html @@ -1,13 +1,13 @@ -Problem:Undetected overflow +Undetected overflow - - - + + + @@ -24,16 +24,28 @@

-Problem:Undetected overflow

+Undetected overflow

A variation of the above is when a value is incremented/decremented beyond it's domain. This is a common problem with for loops.

-
void example3(){
-    // problem: undetected overflow in data type
+
#include <cassert>
+#include <stdexcept>
+#include <iostream>
+
+#include "../include/safe_integer.hpp"
+//#include "../include/safe_compare.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    std::cout << "example 2:";
+    std::cout << "undetected overflow in data type" << std::endl;
     try{
         int x = INT_MAX;
         // the following silently produces an incorrect result
         ++x;
-        //std::cout << x << " != " << -1;
+        std::cout << x << " != " << INT_MAX << " + 1" << std::endl;
         detected_msg(false);
     }
     catch(...){
@@ -51,12 +63,16 @@
         std::cout << e.what();
         detected_msg(true);
     }
+    return 0;
 }
 
-

diff --git a/doc/html/tutorial/3.html b/doc/html/tutorial/3.html index 828f099..e49d3fc 100644 --- a/doc/html/tutorial/3.html +++ b/doc/html/tutorial/3.html @@ -1,13 +1,13 @@ -Problem:Implicit conversions change data values +Undetected underflow - - - + + + @@ -20,66 +20,65 @@

-PrevUpHomeNext +PrevUpHomeNext

-Problem:Implicit conversions change data values

-

A simple assign or arithment expression will generally convert all - the terms to the same type. Sometimes this can silently change values. For - example, when a signed data variable contains a negative type, assigning - to a unsigned type will be permitted by any C/C++ compiler but will be - treated as large unsigned value. Most modern compilers will emit a compile - time warning when this conversion is performed. The user may then decide - to change some data types or apply a static_cast. This is - less than satisfactory for two reasons:

-
    -
  • It may be unwield to change all the types to signed or - unsigned.

  • -
  • Litering one's program with static_cast - makes it more difficult to read.

  • -
  • We may believe that our signed type will never contain a - negative value. If we use a static_cast to suppress the - warning, we'll fail to detect a program error when it is commited. - This is aways a risk with casts.

  • -
-

This solution is the same as the above, Just replace instances of - the int with safe<int>.

-
void example2(){
-    // problem: undetected overflow in data type
+Undetected underflow
+

A variation of the above is when a value is incremented/decremented + beyond it's domain. This is a common problem with for loops.

+
#include <cassert>
+#include <stdexcept>
+#include <iostream>
+
+#include "../include/safe_integer.hpp"
+//#include "../include/safe_compare.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    std::cout << "example 3: ";
+    std::cout << "implicit conversions change data values" << std::endl;
+    std::cout << "Not using safe numerics" << std::endl;
     try{
-        int x = INT_MAX;
+        int x = -1000;
         // the following silently produces an incorrect result
-        ++x;
-        //std::cout << x << " != " << -1;
+        char y = x;
         detected_msg(false);
     }
     catch(...){
         assert(false); // never arrive here
     }
-    // solution: replace int with safe<int>
+    // solution: replace int with safe<int> and char with safe<char>
+    std::cout << "Using safe numerics" << std::endl;
     try{
         using namespace boost::numeric;
-        safe<int> x = INT_MAX;
-        // throws exception when result is past maximum possible 
-        ++x;
+        safe<int> x = -1000;
+        // throws exception when conversion change data value
+        safe<char> y = x;
         assert(false); // never arrive here
     }
     catch(std::range_error & e){
-        std::cout << e.what();
+        std::cout << e.what() << std::endl;
         detected_msg(true);
     }
+    return 0;
 }
 
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/tutorial/4.html b/doc/html/tutorial/4.html new file mode 100644 index 0000000..17c6c3a --- /dev/null +++ b/doc/html/tutorial/4.html @@ -0,0 +1,110 @@ + + + +Implicit conversions change data values + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Implicit conversions change data values

+

A simple assignment or arithmetic expression will generally convert + all the terms to the same type. Sometimes this can silently change values. + For example, when a signed data variable contains a negative type, + assigning to a unsigned type will be permitted by any C/C++ compiler but + will be treated as large unsigned value. Most modern compilers will emit a + compile time warning when this conversion is performed. The user may then + decide to change some data types or apply a static_cast. This + is less than satisfactory for two reasons:

+
    +
  • It may be unwieldy to change all the types to signed or + unsigned.

  • +
  • Littering one's program with static_cast + makes it more difficult to read.

  • +
  • We may believe that our signed type will never contain a + negative value. If we use a static_cast to suppress the + warning, we'll fail to detect a program error when it is committed. + This is aways a risk with casts.

  • +
+

This solution is the same as the above, Just replace instances of + the int with safe<int>.

+
#include <cassert>
+#include <stdexcept>
+#include <iostream>
+
+#include "../include/safe_integer.hpp"
+#include "../include/safe_compare.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    std::cout << "example 4:";
+    std::cout << "undetected underflow in data type" << std::endl;
+    std::cout << "Not using safe numerics" << std::endl;
+    try{
+        unsigned int x = 0;
+        // the following silently produces an incorrect result
+        --x;
+        // because C/C++ implicitly converts mis-matched arguments to int
+        // suggests that the operation is correct
+        assert(x == -1);
+        // even though it's not !!!
+
+        // however, safe_compare does detect the error
+        assert(! boost::numeric::safe_compare::equal(x, -1));
+        std::cout << x << " != " << -1;
+        detected_msg(false);
+    }
+    catch(...){
+        assert(false); // never arrive here
+    }
+    // solution: replace unsigned int with safe<unsigned int>
+    std::cout << "Using safe numerics" << std::endl;
+    try{
+        using namespace boost::numeric;
+        safe<unsigned int> x = 0;
+        // decrement unsigned to less than zero throws exception
+        --x;
+        assert(false); // never arrive here
+    }
+    catch(std::range_error & e){
+        std::cout << e.what();
+        detected_msg(true);
+    }
+    return 0;
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/tutorial/5.html b/doc/html/tutorial/5.html new file mode 100644 index 0000000..98b5543 --- /dev/null +++ b/doc/html/tutorial/5.html @@ -0,0 +1,87 @@ + + + +Array index value can exceed array limits + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Array index value can exceed array limits

+

Using an intrinsic C++ array, it's very easy to exceed array limits. + This can fail to be detected when it occurs and create bugs which are hard + to find. There are several ways to address this, but one of the simplest + would be to use safe_unsigned_range;

+
#include <cassert>
+#include <stdexcept>
+#include <iostream>
+
+#include "../include/safe_range.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    // problem: array index values can exceed array bounds
+    std::cout << "example 5: ";
+    std::cout << "array index values can exceed array bounds" << std::endl;
+    std::cout << "Not using safe numerics" << std::endl;
+    int i_array[37];
+
+    unsigned int i_index = 43;
+    // the following corrupts memory.
+    // This may or may not be detected at run time.
+    // i_array[i_index] = 84; // comment this out so it can be tested!
+    detected_msg(false);
+
+    // solution: replace unsigned array index with safe_unsigned_range
+    std::cout << "Using safe numerics" << std::endl;
+    try{
+        using namespace boost::numeric;
+        safe_unsigned_range<0, sizeof(i_array)/sizeof(int) - 1> i_index;
+        i_index = 36; // this works fine
+        i_array[i_index] = 84;
+        i_index = 37; // throw exception here!
+        i_array[i_index] = 84; // so we never arrive here
+        assert(false);
+    }
+    catch(std::range_error & e){
+        std::cout << e.what() << std::endl;
+        detected_msg(true);
+    }
+    return 0;
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/tutorial/6.html b/doc/html/tutorial/6.html new file mode 100644 index 0000000..4da9839 --- /dev/null +++ b/doc/html/tutorial/6.html @@ -0,0 +1,98 @@ + + + +Checking of initialization values can be easily overlooked + + + + + + + + + + + + + + + +
pre-boostHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+

+Checking of initialization values can be easily overlooked

+

It's way too easy to overlook the checking of parameters received + from outside the current program.

+
#include <cassert>
+#include <stdexcept>
+#include <sstream>
+#include <iostream>
+
+#include "../include/safe_integer.hpp"
+
+void detected_msg(bool detected){
+    std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl;
+}
+
+int main(int argc, const char * argv[]){
+    // problem: checking of externally produced value can be overlooked
+    std::cout << "example 6: ";
+    std::cout << "checking of externally produced value can be overlooked" << std::endl;
+    std::cout << "Not using safe numerics" << std::endl;
+
+    std::istringstream is("12317289372189 1231287389217389217893");
+
+    int x, y, z;
+    is >> x >> y; // get integer values from the user
+    z = x + y;
+    std::cout << z << std::endl;  // display sum of the values
+    detected_msg(false);
+    
+    // solution: asign externally retrieved values to safe equivalents
+    std::cout << "Using safe numerics" << std::endl;
+    {
+        using namespace boost::numeric;
+        safe<int> x, y, z;
+        is.seekg(0);
+        try{
+            is >> x >> y; // get integer values from the user
+            detected_msg(false);
+        }
+        catch(std::range_error & e){
+            std::cout << e.what() << std::endl;
+            detected_msg(true);
+        }
+        try{
+            z = x + y;
+            detected_msg(false);
+        }
+        catch(std::exception e){
+            std::cout << z << std::endl;  // display sum of the values
+            detected_msg(true);
+        }
+    }
+    return 0;
+}
+
+

Without + safe integer, one will have to insert new code every time an integer + variable is retrieved. This is a tedious and error prone procedure.

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/types.html b/doc/html/types.html index 44becdd..e10484d 100644 --- a/doc/html/types.html +++ b/doc/html/types.html @@ -6,8 +6,8 @@ - - + + @@ -20,25 +20,30 @@

-PrevUpHomeNext +PrevUpHomeNext
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/examples/example5.cpp b/examples/example5.cpp new file mode 100644 index 0000000..cbe697a --- /dev/null +++ b/examples/example5.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "../include/safe_range.hpp" + +void detected_msg(bool detected){ + std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl; +} + +int main(int argc, const char * argv[]){ + // problem: array index values can exceed array bounds + std::cout << "example 5: "; + std::cout << "array index values can exceed array bounds" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + int i_array[37]; + + unsigned int i_index = 43; + // the following corrupts memory. + // This may or may not be detected at run time. + // i_array[i_index] = 84; // comment this out so it can be tested! + detected_msg(false); + + // solution: replace unsigned array index with safe_unsigned_range + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::numeric; + safe_unsigned_range<0, sizeof(i_array)/sizeof(int) - 1> i_index; + i_index = 36; // this works fine + i_array[i_index] = 84; + i_index = 37; // throw exception here! + i_array[i_index] = 84; // so we never arrive here + assert(false); + } + catch(std::range_error & e){ + std::cout << e.what() << std::endl; + detected_msg(true); + } + return 0; +} diff --git a/examples/example6.cpp b/examples/example6.cpp new file mode 100644 index 0000000..29fad0e --- /dev/null +++ b/examples/example6.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include "../include/safe_integer.hpp" + +void detected_msg(bool detected){ + std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl; +} + +int main(int argc, const char * argv[]){ + // problem: checking of externally produced value can be overlooked + std::cout << "example 6: "; + std::cout << "checking of externally produced value can be overlooked" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + + std::istringstream is("12317289372189 1231287389217389217893"); + + int x, y, z; + is >> x >> y; // get integer values from the user + z = x + y; + std::cout << z << std::endl; // display sum of the values + detected_msg(false); + + // solution: asign externally retrieved values to safe equivalents + std::cout << "Using safe numerics" << std::endl; + { + using namespace boost::numeric; + safe x, y, z; + is.seekg(0); + try{ + is >> x >> y; // get integer values from the user + detected_msg(false); + } + catch(std::range_error & e){ + std::cout << e.what() << std::endl; + detected_msg(true); + } + try{ + z = x + y; + detected_msg(false); + } + catch(std::exception e){ + std::cout << z << std::endl; // display sum of the values + detected_msg(true); + } + } + return 0; +}