[clang] [clang][analyzer] Suppress false positives in std::stable_sort and st… (PR #177804)
Endre Fülöp via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 24 14:27:34 PST 2026
https://github.com/gamesh411 created https://github.com/llvm/llvm-project/pull/177804
…d::inplace_merge
The analyzer reports false positives in `std::stable_sort` and `std::inplace_merge` due to complex move semantics in `__uninitialized_construct_buf_dispatch::__ucr`.
Add suppression for this STL internal function, following the pattern of existing suppressions for `std::basic_string` and `std::shared_ptr`.
>From e3ce3086bf5c545406219bcfc1ceb90befd1d335 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <endre.fulop at sigmatechnology.com>
Date: Sat, 24 Jan 2026 22:38:58 +0100
Subject: [PATCH] [clang][analyzer] Suppress false positives in
std::stable_sort and std::inplace_merge
The analyzer reports false positives in `std::stable_sort` and
`std::inplace_merge` due to complex move semantics in
`__uninitialized_construct_buf_dispatch::__ucr`.
Add suppression for this STL internal function, following the pattern
of existing suppressions for `std::basic_string` and `std::shared_ptr`.
---
.../Core/BugReporterVisitors.cpp | 16 +++++++++
...tem-header-simulator-cxx-std-suppression.h | 35 +++++++++++++++++++
.../implicit-cxx-std-suppression.cpp | 10 ++++++
3 files changed, 61 insertions(+)
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 7df5fab0843ac..65e2ed5a28313 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -3305,6 +3305,22 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
}
}
+ // Suppress false positives in std::stable_sort and std::inplace_merge.
+ // The analyzer reports uninitialized values in the
+ // __uninitialized_construct_buf_dispatch::__ucr method used by those
+ // algorithms due to complex move semantics with placement new.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getName() == "__ucr") {
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(FD->getParent())) {
+ if (RD->getName().starts_with(
+ "__uninitialized_construct_buf_dispatch")) {
+ BR.markInvalid(getTag(), nullptr);
+ return;
+ }
+ }
+ }
+ }
+
for (const LocationContext *LCtx = N->getLocationContext(); LCtx;
LCtx = LCtx->getParent()) {
const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx-std-suppression.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx-std-suppression.h
index dc53af269c9c2..b7d61b2955f3c 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator-cxx-std-suppression.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx-std-suppression.h
@@ -142,5 +142,40 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t) {
}
#endif // __has_feature(cxx_decltype)
+
+// Mock for __uninitialized_construct_buf_dispatch::__ucr suppression.
+// std::stable_sort uses _Temporary_buffer which calls
+// __uninitialized_construct_buf_dispatch::__ucr internally.
+// The analyzer seems to lose track of initialization state in __ucr's complex
+// move semantics, leading to false positives.
+namespace __uninitialized_construct_buf_dispatch_impl {
+template <bool>
+struct __uninitialized_construct_buf_dispatch {
+ template <typename _Pointer, typename _ForwardIterator>
+ static _Pointer __ucr(_Pointer __first, _ForwardIterator __last) {
+ // Fake error trigger.
+ int z = 0;
+ z = 5/z;
+ return __first;
+ }
+};
+} // namespace __uninitialized_construct_buf_dispatch_impl
+
+template <typename _RandomAccessIterator>
+void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
+ // Calls __ucr internally, matching real STL implementation.
+ __uninitialized_construct_buf_dispatch_impl::
+ __uninitialized_construct_buf_dispatch<false>::__ucr(__first, __last);
}
+template <typename _BidirectionalIterator>
+void inplace_merge(_BidirectionalIterator __first,
+ _BidirectionalIterator __middle,
+ _BidirectionalIterator __last) {
+ // Also uses _Temporary_buffer which calls __ucr internally.
+ __uninitialized_construct_buf_dispatch_impl::
+ __uninitialized_construct_buf_dispatch<false>::__ucr(__first, __middle);
+}
+
+} // namespace std
+
diff --git a/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp b/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
index 35f8798c81ae1..f49d6f78c165a 100644
--- a/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
+++ b/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
@@ -37,3 +37,13 @@ void testSuppression_std_shared_pointer() {
p = nullptr; // no-warning
}
+
+void testSuppression_stable_sort() {
+ int arr[5];
+ std::stable_sort(arr, arr + 5); // no-warning
+}
+
+void testSuppression_inplace_merge() {
+ int arr[5];
+ std::inplace_merge(arr, arr + 2, arr + 5); // no-warning
+}
More information about the cfe-commits
mailing list