public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Fix conditions for using memcmp in std::lexicographical_compare_three_way [PR113960]
@ 2024-02-29 17:49 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2024-02-29 17:49 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested aarch64-linux, powerpc-linux (power 7 BE), x86_64-linux.
The bug reporter tested it on s390x too.

Pushed to trunk. This should be backported too.

-- >8 --

The change in r11-2981-g2f983fa69005b6 meant that
std::lexicographical_compare_three_way started to use memcmp for
unsigned integers on big endian targets, but for that to be valid we
need the two value types to have the same size and we need to use that
size to compute the length passed to memcmp.

I already defined a __is_memcmp_ordered_with trait that does the right
checks, std::lexicographical_compare_three_way just needs to use it.

libstdc++-v3/ChangeLog:

	PR libstdc++/113960
	* include/bits/stl_algobase.h (__is_byte_iter): Replace with ...
	(__memcmp_ordered_with): New concept.
	(lexicographical_compare_three_way): Use __memcmp_ordered_with
	instead of __is_byte_iter. Use correct length for memcmp.
	* testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc:
	New test.
---
 libstdc++-v3/include/bits/stl_algobase.h      | 41 ++++++++++---------
 .../113960.cc                                 | 15 +++++++
 2 files changed, 37 insertions(+), 19 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc

diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d534e02871f..74ff42d4f39 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1806,11 +1806,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
     }
 
 #if __cpp_lib_three_way_comparison
-  // Iter points to a contiguous range of unsigned narrow character type
-  // or std::byte, suitable for comparison by memcmp.
-  template<typename _Iter>
-    concept __is_byte_iter = contiguous_iterator<_Iter>
-      && __is_memcmp_ordered<iter_value_t<_Iter>>::__value;
+  // Both iterators refer to contiguous ranges of unsigned narrow characters,
+  // or std::byte, or big-endian unsigned integers, suitable for comparison
+  // using memcmp.
+  template<typename _Iter1, typename _Iter2>
+    concept __memcmp_ordered_with
+      = (__is_memcmp_ordered_with<iter_value_t<_Iter1>,
+				  iter_value_t<_Iter2>>::__value)
+	  && contiguous_iterator<_Iter1> && contiguous_iterator<_Iter2>;
 
   // Return a struct with two members, initialized to the smaller of x and y
   // (or x if they compare equal) and the result of the comparison x <=> y.
@@ -1860,20 +1863,20 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
       if (!std::__is_constant_evaluated())
 	if constexpr (same_as<_Comp, __detail::_Synth3way>
 		      || same_as<_Comp, compare_three_way>)
-	  if constexpr (__is_byte_iter<_InputIter1>)
-	    if constexpr (__is_byte_iter<_InputIter2>)
-	      {
-		const auto [__len, __lencmp] = _GLIBCXX_STD_A::
-		  __min_cmp(__last1 - __first1, __last2 - __first2);
-		if (__len)
-		  {
-		    const auto __c
-		      = __builtin_memcmp(&*__first1, &*__first2, __len) <=> 0;
-		    if (__c != 0)
-		      return __c;
-		  }
-		return __lencmp;
-	      }
+	  if constexpr (__memcmp_ordered_with<_InputIter1, _InputIter2>)
+	    {
+	      const auto [__len, __lencmp] = _GLIBCXX_STD_A::
+		__min_cmp(__last1 - __first1, __last2 - __first2);
+	      if (__len)
+		{
+		  const auto __blen = __len * sizeof(*__first1);
+		  const auto __c
+		    = __builtin_memcmp(&*__first1, &*__first2, __blen) <=> 0;
+		  if (__c != 0)
+		    return __c;
+		}
+	      return __lencmp;
+	    }
 
       while (__first1 != __last1)
 	{
diff --git a/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc
new file mode 100644
index 00000000000..d51ae1a3d50
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++20 } }
+
+// PR libstdc++/113960
+// std::map with std::vector as input overwrites itself with c++20, on s390x
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  unsigned short a1[] { 1, 2, 3 };
+  unsigned short a2[] { 1, 2, 4 };
+  // Incorrect memcmp comparison for big endian targets.
+  VERIFY( std::lexicographical_compare_three_way(a1, a1+3, a2, a2+3) < 0 );
+}
-- 
2.43.2


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-02-29 17:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-29 17:49 [committed] libstdc++: Fix conditions for using memcmp in std::lexicographical_compare_three_way [PR113960] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).