https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123991
Bug ID: 123991
Summary: std::string::compare crashes instead of throwing
Product: gcc
Version: 15.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: travis.downs at gmail dot com
Target Milestone: ---
libstdc++ std::string::compare(pos, len, string_view) has incorrect noexcept
Summary
-------
Out of range access in std::string::compare(size_t pos, size_t count,
std::string_view sv)
causes terminate() to be called due to incorrect noexcept clause, instead of
propagating
std::out_of_range as required by the standard.
Environment
-----------
Compiler: g++ 15
Standard library: libstdc++
Platform: Linux x86_64
Root Cause
----------
The libstdc++ implementation of std::string::compare(pos, count, string_view)
is:
int compare(size_type pos, size_type n, basic_string_view<CharT, Traits>
sv) const {
return basic_string_view<CharT, Traits>(*this).substr(pos,
n).compare(sv);
}
When pos > size(), string_view::substr() throws std::out_of_range. However, due
to
an incorrect noexcept specification somewhere in the call chain, the exception
triggers std::terminate() instead of propagating to the caller.
Reproducer
----------
// string_view_compare_bug.cc
// Compile: g++ -std=c++20 string_view_compare_bug.cc -o test
// Run: ./test
#include <iostream>
#include <stdexcept>
#include <string>
#include <string_view>
int main() {
std::string s; // empty string, size() == 0
try {
std::string_view sv("");
(void)s.compare(1, 0, sv); // pos=1 > size()=0, should throw
out_of_range
} catch (const std::out_of_range&) {
std::cout << "Exception caught (OK)" << std::endl;
}
return 0;
}
Expected Output
---------------
Exception caught (OK)
Actual Output
-------------
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string_view::substr: __pos (which is 1) > __size (which is 0)
C++ Standard References
-----------------------
Per [string.compare] (N4950 23.4.3.8.8):
template<class T>
constexpr int compare(size_type pos1, size_type n1, const T& t) const;
Throws: out_of_range if pos1 > size()
The exception should be catchable per standard exception handling rules.
Notes
-----
- The issue does NOT occur with libc++ (only libstdc++)
- Other methods like at(), substr() on std::string work correctly
- Godbolt: https://godbolt.org/z/xTWY14h16