https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91357

            Bug ID: 91357
           Summary: _GLIBCXX_ASSERTIONS rejects possibly-valid code
           Product: gcc
           Version: 9.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: luto at kernel dot org
  Target Milestone: ---

Created attachment 46672
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46672&action=edit
Example

For a non-empty vector v, calling v.operator[](v.size()) fires this assertion:

/usr/include/c++/9/bits/stl_vector.h:1042: std::vector<_Tp, _Alloc>::reference
std::vector<_Tp, _Alloc>::operator[](std::vector<_Tp, _Alloc>::size_type) [with
_Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::reference =
int&; std::vector<_Tp, _Alloc>::size_type = long unsigned int]: Assertion
'__builtin_expect(__n < this->size(), true)' failed.

After some digging into the standard, I'm not entirely sure whether that
particular invocation of operator[] is UB or otherwise invalid.  It's certainly
poor form -- the right way in modern C++ to form a one-past-the-end pointer to
a vector is (v.data() + v.size()), but, if it's indeed legal, then
_GLIBCXX_ASSERTIONS should not be firing.

I suggest one of the following resolutions:

1. Determine that merely calling v.operator[](v.size()) is UB or that it is
otherwise permissible for a conforming implementation to crash when this
happens.  This would require some careful standard reading and maybe even a
change to the standard.

2. Weaken the assertion to only crash if the index is strictly greater than the
size.  Calling v.operator[](v.size() + 1) is definitely UB (except perhaps in
the pathological case where v.size() + 1 == 0, but I doubt it's possible to
make a vector that large on any supported platform).

3. Use compiler magic to only fire the assertion if the pointer returned by
operator[] is dereferenced for real, e.g. dereferenced and converted to an
lvalue.  Maybe gcc could gain a builtin like
__builtin_return_value_is_definitely_dereferenced().

4. Improve the assertion so that, when this assertion fires, a very clear
message is printed to stderr saying something like "This assertion fired due to
the formation of a one-past-the-end reference.  This may indicate a stylistic
issue with the program but is not necessarily a bug."

Reply via email to