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

Reply via email to