Ensure to have handling for exceptional floating-point values.
The float class has the capability to interpret various input values as floating-point numbers. Some special cases can interpret input values as
NaN (Not-a-Number)These floating-point class values represent numbers that fall outside the typical range and exhibit unique behaviors. NaN (Not a Number) lacks a defined order and is not considered equal to any value, including itself. Hence, evaluating an expression such as NaN == NaN returns False.
The noncompliant01.py intent is to ensure that adding objects will not exceed a total weight of 100 units. Validation fails as the code to test for exceptional conditions, such as NaN or infinity, is missing.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Non-compliant Code Example"""
 
import sys
 
 
class Package:
    """Class representing a package object"""
 
    def __init__(self):
        self.package_weight: float = 0.0
        self.max_package_weight: float = 100.0
 
    def add_to_package(self, object_weight: str):
        """Function for adding an object into the package"""
        value = float(object_weight)
        # This is dead code as value gets type cast to float,
        # hence will never be equal to string "NaN"
        if value == "NaN":
            raise ValueError("'NaN' not a number")
        # This is also dead code as value is type cast to float,
        # unusual inputs like -infinity will not get caught
        if isinstance(value, float) is False:
            raise ValueError("not a number")
        if self.package_weight + value > self.max_package_weight:
            raise ValueError("Addition would exceed maximum package weight.")
 
        self.package_weight += value
 
    def get_package_weight(self):
        """Getter for outputting the package's current weight"""
        return self.package_weight
 
 
#####################
# exploiting above code example
#####################
package = Package()
print(f"\nOriginal package's weight is {package.get_package_weight():.2f} units\n")
for item in [100, "-infinity", sys.float_info.max, "NaN", -100]:
    print(f"package.add_to_package({item})")
    try:
        package.add_to_package(item)
        print(
            f"package.get_package_weight() = {package.get_package_weight():.2f}\n"
        )
 
    except Exception as e:
        print(e)
Some important considerations when dealing with floating-point values from non-complaint01.py.
sys.float_info.max does not increase the held value. In some cases, incrementing package_weight with a high enough value may turn its value into inf.-infinity and +infinity causes the value of the package_weight to be infinite as well."NaN", which is not a valid value to package_weight will always return "nan".Example noncompliant01.py output:
Original package's weight is 0.00 units
package.add_to_package(100)
package.get_package_weight() = 100.00
package.add_to_package(-infinity)
package.get_package_weight() = -inf
package.add_to_package(1.7976931348623157e+308)
package.get_package_weight() = -inf
package.add_to_package(NaN)
package.get_package_weight() = nan
package.add_to_package(-100)
package.get_package_weight() = nan
Exceptional values and out-of-range values are handled in compliant01.py. Some negative values are also checked for due to the nature of the code example.
The isfinite function from the math library is useful for checking for NaN, infinity and -infinity values. math.isfinite checks if a value is neither infinite nor a NaN.
Other functions from the math library that could be of use are isnan, which checks if an inputted value is "NaN", and isinf (which checks if a value is positive or negative infinity).
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Compliant Code Example """
import sys
from math import isfinite, isnan
from typing import Union
class Package:
    """Class representing a package object."""
    def __init__(self) -> None:
        self.package_weight: float = 0.0
        self.max_package_weight: float = 100.0
    def add_to_package(self, object_weight: Union[str, int, float]) -> None:
        # TODO: input sanitation.
        # TODO: proper exception handling
        """Add an object into the package after validating its weight."""
        try:
            value = float(object_weight)
        except (ValueError, TypeError) as e:
            raise ValueError("Input cannot be converted to a float.") from e
        if isnan(value):
            raise ValueError("Input is not a number")
        if not isfinite(value):
            raise ValueError("Input is not a finite number.")
        if value < 0:
            raise ValueError("Weight must be a non-negative number.")
        if self.package_weight + value > self.max_package_weight:
            raise ValueError("Addition would exceed maximum package weight.")
 
        print(f"Adding an object that weighs {value} units to package")
        self.package_weight += value
 
    def get_package_weight(self) -> float:
        """Return the package's current weight."""
        return self.package_weight
#####################
# exploiting above code example
#####################
 
 
package = Package()
print(f"\nOriginal package's weight is {package.get_package_weight():.2f} units\n")
for item in [100, "-infinity", sys.float_info.max, "NaN", -100]:
    print(f"package.add_to_package({item})")
    try:
        package.add_to_package(item)
        print(
            f"package.get_package_weight() = {package.get_package_weight():.2f}\n"
        )
 
    except Exception as e:
        print(e)
This compliant code example will raise a ValueError for inputs that are -infinity, infinity, or NaN, with messages “Input is not a finite number” and “Input is not a number” respectively. It should also ensure weights are non-negative, returning “Weight must be a non-negative number” for negative inputs.
Example compliant01.py output:
Original package's weight is 0.00 units
 
package.add_to_package(100)
Adding an object that weighs 100.0 units to package
package.get_package_weight() = 100.00
 
package.add_to_package(-infinity)
Input is not a finite number.
package.add_to_package(1.7976931348623157e+308)
Addition would exceed maximum package weight.
package.add_to_package(NaN)
Input is not a number
package.add_to_package(-100)
Weight must be a non-negative number.
| Tool | Version | Checker | Description | 
| bandit | 1.7.4 | no detection |