...
The index operators
...
std::string
index operators const_reference
...
operator[](size_type
...
)
...
const
...
and reference
...
operator[](size_type
...
return )
return the character stored at the specified position if , pos < size()
. If When pos >= = size()
, the const
version returns the terminating null character type value. Otherwise, the behavior is undefined.In any case, the behavior of the index operators is a reference to an object of type charT
with value charT()
is returned. The index operators are unchecked (no exceptions are thrown for range errors).
Non-Compliant Code Example
, and attempting to modify the resulting out-of-range object results in undefined behavior.
Similarly, the std::string::back()
and std::string::front()
functions are unchecked as they are defined to call through to the appropriate operator[]()
without throwing.
Do not pass an out-of-range value as an argument to std::string::operator[]()
. Similarly, do not call std::string::back()
or std::string::front()
on an empty string. This rule is a specific instance of CTR50-CPP. Guarantee that container indices and iterators are within the valid range.
Noncompliant Code Example
In this noncompliant code example, the value returned by the call to get_index()
may be greater than the number of elements stored in the string, resulting in undefined behaviorThe behavior of this non-compliant example is undefined because the index i
used to reference bs
may be outside the range of bs
, causing a write-out-of-bounds error.
Code Block | ||||
---|---|---|---|---|
| ||||
string bs("01234567"); size_t i = f(); bs[i#include <string> extern std::size_t get_index(); void f() { std::string s("01234567"); s[get_index()] = '\01'; |
This program does not typically raise an exception and may be exploited to overwrite memory at a specified location.
Compliant Solution
} |
Compliant Solution (try
/catch
)
This compliant solution uses the std::basic_string::at()
function, which behaves in a similar fashion to the index operator[]
but throws a std::
This compliant solution uses the {{basic_string at()}} method, which behaves in a similar fashion to the index {{operator\[\]}} but throws an {{ Wiki Markup out_of_range
}} exception if {{pos >= pos >= size()
}}.
Code Block | ||||
---|---|---|---|---|
| ||||
string bs("01234567"); try#include <stdexcept> #include <string> extern std::size_t get_index(); void f() { size_t i = f(); bs.at(istd::string s("01234567"); try { s.at(get_index()) = '\01'; } catch (...std::out_of_range &) { cerr << "Index out of range" << endl; } |
In any case, the behavior of the index operators is unchecked (no exceptions are thrown).
Non-Compliant Code Example
The behavior of this non-compliant example is undefined because the size()
of bs
is 8 but the index used to reference bs
ranges from 0 through 99.
// Handle error
}
} |
Compliant Solution (Range Check)
This compliant solution checks that the value returned by get_index()
is within a valid range before calling operator[]().
Code Block | ||||
---|---|---|---|---|
| ||||
#include <string>
extern std::size_t get_index();
void f() {
std::string s("01234567");
std::size_t i = get_index();
if (i < s.length()) {
s | ||||
Code Block | ||||
| ||||
string bs("01234567"); for (int i=0; i < 100; i++) { bs[i] = '\01'; } else { // Handle error } |
This program does not typically raise an exception and is likely to crash.
Compliant Solution
} |
Noncompliant Code Example
This noncompliant code example attempts to replace the initial character in the string with a capitalized equivalent. However, if the given string is empty, the behavior is undefined.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <string>
#include <locale>
void capitalize(std::string &s) {
std::locale loc;
s.front() = std::use_facet<std::ctype<char>>(loc).toupper(s.front());
} |
Compliant Solution
In this compliant solution, the call to std::string::front()
is made only if the string is not empty.Use the fill algorithm to assign the value '\0'
to evey element in the specified range:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <string> #include <locale> void capitalize( size_t const max_fill = 100; std::string bs("01234567"); fill(bs.begin(), bs.begin()+std::min(max_fill, bs.length()), '\0' ); |
...
&s) {
if (s.empty()) {
return;
}
std::locale loc;
s.front() = std::use_facet<std::ctype<char>>(loc).toupper(s.front());
} |
Risk Assessment
Unchecked element access can lead to out-of-bounds bound reads and writes and write-anywhere exploits. These exploits can, in turn, lead to the execution of arbitrary code with the permissions of the vulnerable process.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
STR53- |
3 (high)
3 (likely)
1 (high)
P9
L2
References
Wiki Markup |
---|
\[[Seacord 05|AA. C++ References#Seacord 05]\] Chapter 2 Strings
\[[ISO/IEC 14882-2003|AA. C++ References#ISO/IEC 14882-2003]\] Section 21.3.4 basic_string element access |
CPP | High | Unlikely | Medium | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| assert_failure | |||||||
CodeSonar |
| LANG.MEM.BO | Buffer overrun Buffer underrun Tainted buffer access Type overrun Type underrun | ||||||
Helix QAC |
| C++3162, C++3163, C++3164, C++3165 | |||||||
Parasoft C/C++test |
| CERT_CPP-STR53-a | Guarantee that container indices are within the valid range | ||||||
Polyspace Bug Finder |
| CERT C++: STR53-CPP | Checks for:
Rule partially covered. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | CTR50-CPP. Guarantee that container indices and iterators are within the valid range |
Bibliography
[ISO/IEC 14882-2014] | Subclause 21.4.5, " |
[Seacord 2013] | Chapter 2, "Strings" |
...
BSC33-C. Use valid references, pointers, and iterators to reference string objects 07. Characters and Strings (STR) 08. Memory Management (MEM)