2244
Scope Impact Likelihood
The results of the math are not as expected. This could
cause issues where a value would not be properly
calculated and provide an incorrect answer.
Confidentiality
Availability
Access Control
Read Application Data
Modify Application Data
This weakness can sometimes trigger buffer overflows
which can be used to execute arbitrary code. This is
usually outside the scope of a product's implicit security
policy.
Potential Mitigations
Phase: Implementation
Phase: Patching and Maintenance
The developer or maintainer can move to a more accurate representation of real numbers. In
extreme cases, the programmer can move to representations such as ratios of BigInts which can
represent real numbers to extremely fine precision. The programmer can also use the concept of
an Unum real. The memory and CPU tradeoffs of this change must be examined. Since floating
point reals are used in many products and many locations, they are implemented in hardware
and most format changes will cause the calculations to be moved into software resulting in
slower products.
Demonstrative Examples
Example 1:
Muller's Recurrence is a series that is supposed to converge to the number 5. When running this
series with the following code, different implementations of real numbers fail at specific iterations:
Example Language: Rust (Bad)
fn rec_float(y: f64, z: f64) -> f64
{
108.0 - ((815.0 - 1500.0 / z) / y);
}
fn float_calc(turns: usize) -> f64
{
let mut x: Vec<f64> = vec![4.0, 4.25];
(2..turns + 1).for_each(|number|
{
x.push(rec_float(x[number - 1], x[number - 2]));
});
x[turns]
}
The chart below shows values for different data structures in the rust language when Muller's
recurrence is executed to 80 iterations. The data structure f64 is a 64 bit float. The data structures
I<number>F<number> are fixed representations 128 bits in length that use the first number as
the size of the integer and the second size as the size of the fraction (e.g. I16F112 uses 16 bits
for the integer and 112 bits for the fraction). The data structure of Ratio comes in three different
implementations: i32 uses a ratio of 32 bit signed integers, i64 uses a ratio of 64 bit signed integers
and BigInt uses a ratio of signed integer with up to 2^32 digits of base 256. Notice how even with
112 bits of fractions or ratios of 64bit unsigned integers, this math still does not converge to an
expected value of 5.
Example Language: Rust (Good)
Use num_rational::BigRational;
fn rec_big(y: BigRational, z: BigRational) -> BigRational
{
CWE Version 4.14
CWE-1339: Insufficient Precision or Accuracy of a Real Number
CWE-1339: Insufficient Precision or Accuracy of a Real Number