Main Content

CERT C++: ERR62-CPP

Detect errors when converting a string to a number

Since R2023b

Description

Rule Definition

Detect errors when converting a string to a number.1

Polyspace Implementation

The rule checker checks for the issue String-to-number conversion not validated.

Examples

expand all

Issue

The issue occurs when you perform string-to-number conversion using the formatted input stream std::basic_istream and the locale facet num_get<> but do not check for errors. For instance, Polyspace® reports a violation when:

  • You call the formatted input operator std::basic_istream::operator>> but do not check for conversion exception. This can include calling the operator outside a try-catch block, or failing to activate the conversion exceptionsstd::basic_ios<>::exceptions().

  • You call the formatted input operator std::basic_istream::operator>> but do not check for conversion errors by calling one of std::basic_ios::good(), std::basic_ios::bad(), or std::basic_ios::fail().

  • You use num_get<> but do not test the output argument ios_base::iostate& for possible errors.

Risk

String-to-number conversions can produce errors such as:

  • The string might not contain valid numbers.

  • The number might be out of range for the destination type.

  • The string might contain extra information after the number.

Unexpected behavior can occur if you assume that string-to-number conversions result in a valid state without checking for errors.

Fix

To fix this violation, check the string-to-number conversion for errors when using :

  • When using the operator std::basic_istream::operator>>, check for conversion exception by enclosing the operator std::basic_istream::operator>> in a try-catch block and enabling the conversion exception std::basic_ios<>::exceptions() within a try-catch block and activate the conversion exceptions.

  • Alternatively, when using the operator std::basic_istream::operator>>, check for conversion error by calling one of these functions: std::basic_ios::good(), std::basic_ios::bad(), or std::basic_ios::fail()

  • After calling num_get<>, use the output ios_base::iostate& in a test condition.

Example — std::basic_istream::operator>> Can Throw Uncaught Exceptions

This example code performs string-to-number conversion by using std::basic_istream::operator>> outside a try-catch block. An exception arising from the std::basic_istream::operator>> operator becomes an uncaught exception, causing the program to terminate prematurely. Because the code calls std::basic_istream::operator>> outside a try-catch block, Polyspace reports violations of this rule.

#include <iostream>
void stringConversionNotValidated(){
	int i,j;
	//...
	std::cin>>i;
	
	try{
		std::cin>>j;  //Noncompliant
	}catch (std::istream::failure &E) {
    // Handle error
  }
	
}//Noncompliant
Correction — Check calls to std::basic_istream::operator>> for conversion exceptions

Fix the violations by checking for exceptions when using std::basic_istream::operator>>. In this example code, calls to std::cin>> take place within a try-catch block. Because this code activates std::cin.exceptions, conversion exceptions are caught and handled in the catch block.

#include <iostream>
void stringConversionValidated() {
  int i, j;
 
  std::cin.exceptions(std::istream::failbit | std::istream::badbit);
  try {    
    std::cin >> i >> j;
    // ...
  } catch (std::istream::failure &E) {
    // Handle error
  }
}
Correction — Check for Conversion Error Using std::basic_ios::fail()

Fix the violations by checking for conversion errors when using std::basic_istream::operator>>. In this example code, after calling std::cin>>, the function std::cin.fail() is called in an if block to check for and handle conversion errors.

#include <iostream>
void stringConversionNotValidated(){
	int i,j;
	//...
	std::cin>>i;
	 if (std::cin.fail()) {
    // Handle failure to convert the value.

  }
	try{
		std::cin>>j;  //Compliant
		if (std::cin.fail()) {
    // Handle failure to convert the value.

  }
	}catch (std::istream::failure &E) {
    // Handle error
  }
	
}//Compliant	
Example — Untested Calls to std::num_get<>::get()

In this example, the function numGetNotTested() calls std::num_get<>::get() to convert strings to numbers, but does not check if the operation results in a valid state. Polyspace reports a violation.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <locale>
#include <iterator>

void numGetNotTested(std::string& str){
    std::istringstream s(str);
    s.imbue(std::locale()); // using default "C" locale
    auto& fac = std::use_facet<std::num_get<char>>(s.getloc());
    std::istreambuf_iterator<char> beg(s), end;
    double f;
    std::ios::iostate err = std::ios_base::goodbit;
    fac.get(beg, end, s, err, f); 
	
}//Noncompliant 

Correction — Check for Errors After Calling std::num_get<>::get()

To fix this violation, check the call to std::num_get<>::get() for errors. For instance, in this code, after calling fac.get(), the error state of the call is tested in the if() block. Polyspace does not report a violation.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <locale>
#include <iterator>

void numGetTested(std::string& str){
    std::istringstream s(str);
    s.imbue(std::locale()); // using default "C" locale
    auto& fac = std::use_facet<std::num_get<char>>(s.getloc());
    std::istreambuf_iterator<char> beg(s), end;
    double f;
    std::ios::iostate err = std::ios_base::goodbit;
    fac.get(beg, end, s, err, f); 
	if (err == std::ios_base::badbit) {
        //...
    }
} 

Check Information

Group: 08. Exceptions and Error Handling (ERR)

Version History

Introduced in R2023b


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.