Libstdc++: Avoid past-the-end iterator dereference with overloaded operator&&.
Libstdc++ algorithms now prevent dereferencing past-the-end iterators when custom operator&& is used in loop conditions.
This commit addresses an issue in libstdc++ algorithms like std::__find_if and std::__mismatch where custom overloaded operator&& could lead to dereferencing past-the-end iterators. Such custom operators, if not designed for short-circuiting, would evaluate their operands even when the loop condition indicated the end of the range. The fix forces the predicate result to bool, ensuring the use of the built-in, short-circuiting && operator and preventing the dereference of invalid iterators.
In Details
Algorithms such as std::__find_if, std::__mismatch, and std::__push_heap in libstdc++ were vulnerable to dereferencing past-the-end iterators when a user-defined operator&& was selected via ADL for the loop condition. This operator&& did not necessarily short-circuit, causing the loop body or predicate evaluation to execute even when __first == __last. By coercing the predicate/comparator result to bool, the compiler is forced to use the built-in &&, which guarantees short-circuiting and resolves the undefined behavior.
- past-the-end iterator
- An iterator that points one position beyond the last element of a container or range. It is typically used to signify the end of the range but is not dereferenceable.
- operator&&
- The logical AND operator. When overloaded, it allows user-defined types to participate in logical AND expressions. Standard C++
&&is short-circuiting. - ADL (Argument-Dependent Lookup)
- A C++ name lookup rule that considers functions and operators in namespaces associated with the types of function arguments, in addition to other namespaces.
- short-circuiting
- A characteristic of logical operators where the second operand is not evaluated if the result of the expression can be determined solely by the first operand. For
&&, if the left operand is false, the right is not evaluated. - boolean-testable
- A concept in C++20 that describes types that can be unambiguously converted to bool, suitable for use in logical operations.