https://github.com/gamesh411 updated 
https://github.com/llvm/llvm-project/pull/178910

From 7b5b9e715f677dd2a60908327059fc1848d2a39e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <[email protected]>
Date: Fri, 30 Jan 2026 12:02:57 +0100
Subject: [PATCH 1/2] [clang][analyzer] Add OpaqueSTLFunctionsModeling

This modeling checker is the intended place for suppressing internal
STL-specific implementation-detail functions that cannot be modeled
adequately by the engine.

If possible, using `evalCall` to not even emit the false positives is
more efficient than suppressing them after analysis in
`BugReporterVisitor`s, so this modeling checker takes that route.

This patch introduces the conservative evaluation (no inlining) for
`__uninitialized_construct_buf_dispatch::__ucr`, an STL internal
function used by `std::stable_sort` and `std::inplace_merge` that
causes false positives.

Related to #177804.
---
 .../clang/StaticAnalyzer/Checkers/Checkers.td |  6 ++
 .../StaticAnalyzer/Checkers/CMakeLists.txt    |  1 +
 .../Checkers/OpaqueSTLFunctionsModeling.cpp   | 76 +++++++++++++++++++
 ...tem-header-simulator-cxx-std-suppression.h | 28 +++++++
 .../implicit-cxx-std-suppression.cpp          | 10 +++
 .../opaque-stl-functions-modeling-tag.cpp     | 14 ++++
 6 files changed, 135 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
 create mode 100644 
clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 6a409944849e6..99dbae1dbf8b7 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -674,6 +674,12 @@ def PureVirtualCallChecker
       HelpText<
           "Check pure virtual function calls during construction/destruction">,
       Documentation<HasDocumentation>;
+
+def OpaqueSTLFunctionsModeling : Checker<"OpaqueSTLFunctionsModeling">,
+  HelpText<"Force opaque, conservative evaluation for STL internal 
implementation functions">,
+  Documentation<NotDocumented>,
+  Hidden;
+
 } // end: "cplusplus"
 
 let ParentPackage = CplusplusOptIn in {
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 2df36d8e672ae..3edbd7ebdc1bf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -86,6 +86,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   ObjCSelfInitChecker.cpp
   ObjCSuperDeallocChecker.cpp
   ObjCUnusedIVarsChecker.cpp
+  OpaqueSTLFunctionsModeling.cpp
   OSObjectCStyleCast.cpp
   PaddingChecker.cpp
   PointerArithChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
new file mode 100644
index 0000000000000..0e4f8c4bbc4d3
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
@@ -0,0 +1,76 @@
+//===--- OpaqueSTLFunctionsModeling.cpp 
-----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Forces conservative evaluation for STL internal implementation functions
+// (prefixed with '__') known to cause false positives. This prevents inlining
+// of complex STL internals and avoids wasting analysis time spent in
+// `BugReporterVisitor`s.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class OpaqueSTLFunctionsModeling : public Checker<eval::Call> {
+public:
+  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+
+private:
+  bool shouldForceConservativeEval(const CallEvent &Call) const;
+};
+} // anonymous namespace
+
+bool OpaqueSTLFunctionsModeling::evalCall(const CallEvent &Call,
+                                          CheckerContext &C) const {
+  if (!shouldForceConservativeEval(Call))
+    return false;
+
+  ProgramStateRef State = C.getState();
+  State = Call.invalidateRegions(C.blockCount(), State);
+  static const SimpleProgramPointTag OpaqueCallTag{getDebugTag(),
+                                                   "Forced Opaque Call"};
+  C.addTransition(State, &OpaqueCallTag);
+  return true;
+}
+
+bool OpaqueSTLFunctionsModeling::shouldForceConservativeEval(
+    const CallEvent &Call) const {
+  const Decl *D = Call.getDecl();
+  if (!D || !AnalysisDeclContext::isInStdNamespace(D))
+    return false;
+
+  // __uninitialized_construct_buf_dispatch::__ucr is used by stable_sort
+  // and inplace_merge.
+  if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
+    if (const IdentifierInfo *II = MD->getIdentifier()) {
+      if (II->getName() == "__ucr") {
+        const CXXRecordDecl *RD = MD->getParent();
+        if 
(RD->getName().starts_with("__uninitialized_construct_buf_dispatch"))
+          return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void ento::registerOpaqueSTLFunctionsModeling(CheckerManager &Mgr) {
+  Mgr.registerChecker<OpaqueSTLFunctionsModeling>();
+}
+
+bool ento::shouldRegisterOpaqueSTLFunctionsModeling(const CheckerManager &Mgr) 
{
+  return Mgr.getLangOpts().CPlusPlus;
+}
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..f4e3454f905b5 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,33 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t) {
 }
 
 #endif // __has_feature(cxx_decltype)
+
+// __uninitialized_construct_buf_dispatch::__ucr is used by stable_sort
+// and inplace_merge.
+template<typename _Tp>
+struct __uninitialized_construct_buf_dispatch {
+  template<typename _ForwardIterator, typename _Allocator>
+  static void __ucr(_ForwardIterator __first, _ForwardIterator __last,
+                    _Allocator& __a) {
+    // Fake error trigger
+    int z = 0;
+    z = 5/z;
+  }
+};
+
+template<typename _RandomAccessIterator>
+void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
+  allocator<int> alloc;
+  __uninitialized_construct_buf_dispatch<int>::__ucr(__first, __last, alloc);
+}
+
+template<typename _BidirectionalIterator>
+void inplace_merge(_BidirectionalIterator __first,
+                   _BidirectionalIterator,
+                   _BidirectionalIterator __last) {
+  allocator<int> alloc;
+  __uninitialized_construct_buf_dispatch<int>::__ucr(__first, __last, alloc);
+}
+
 }
 
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
+}
diff --git 
a/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp 
b/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp
new file mode 100644
index 0000000000000..bab43b0622b8d
--- /dev/null
+++ b/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,cplusplus.OpaqueSTLFunctionsModeling \
+// RUN:   -analyzer-dump-egraph=%t.dot -std=c++11 %s
+// RUN: cat %t.dot | FileCheck %s
+
+#include "../Inputs/system-header-simulator-cxx-std-suppression.h"
+
+void testOpaqueSTLTags() {
+  int arr[5];
+  std::stable_sort(arr, arr + 5);
+// CHECK: \"tag\": \"cplusplus.OpaqueSTLFunctionsModeling : Forced Opaque 
Call\"
+  std::inplace_merge(arr, arr + 2, arr + 5);
+// CHECK: \"tag\": \"cplusplus.OpaqueSTLFunctionsModeling : Forced Opaque 
Call\"
+}
+

From dd1b74a4ed7824bb45af18253c341f3107313583 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <[email protected]>
Date: Mon, 2 Feb 2026 15:23:14 +0100
Subject: [PATCH 2/2] simplify: handle only sort and stable_sort

---
 .../Checkers/OpaqueSTLFunctionsModeling.cpp   | 29 ++++---------------
 ...tem-header-simulator-cxx-std-suppression.h | 28 ++----------------
 .../implicit-cxx-std-suppression.cpp          |  8 ++---
 .../opaque-stl-functions-modeling-tag.cpp     |  4 +--
 4 files changed, 15 insertions(+), 54 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
index 0e4f8c4bbc4d3..505370f8805c2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/OpaqueSTLFunctionsModeling.cpp
@@ -17,6 +17,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 
@@ -29,13 +30,16 @@ class OpaqueSTLFunctionsModeling : public 
Checker<eval::Call> {
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
 
 private:
-  bool shouldForceConservativeEval(const CallEvent &Call) const;
+  using CDM = CallDescription::Mode;
+  const CallDescriptionSet ModeledFunctions{
+      {CDM::SimpleFunc, {"std", "sort"}},
+      {CDM::SimpleFunc, {"std", "stable_sort"}}};
 };
 } // anonymous namespace
 
 bool OpaqueSTLFunctionsModeling::evalCall(const CallEvent &Call,
                                           CheckerContext &C) const {
-  if (!shouldForceConservativeEval(Call))
+  if (!ModeledFunctions.contains(Call))
     return false;
 
   ProgramStateRef State = C.getState();
@@ -46,27 +50,6 @@ bool OpaqueSTLFunctionsModeling::evalCall(const CallEvent 
&Call,
   return true;
 }
 
-bool OpaqueSTLFunctionsModeling::shouldForceConservativeEval(
-    const CallEvent &Call) const {
-  const Decl *D = Call.getDecl();
-  if (!D || !AnalysisDeclContext::isInStdNamespace(D))
-    return false;
-
-  // __uninitialized_construct_buf_dispatch::__ucr is used by stable_sort
-  // and inplace_merge.
-  if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
-    if (const IdentifierInfo *II = MD->getIdentifier()) {
-      if (II->getName() == "__ucr") {
-        const CXXRecordDecl *RD = MD->getParent();
-        if 
(RD->getName().starts_with("__uninitialized_construct_buf_dispatch"))
-          return true;
-      }
-    }
-  }
-
-  return false;
-}
-
 void ento::registerOpaqueSTLFunctionsModeling(CheckerManager &Mgr) {
   Mgr.registerChecker<OpaqueSTLFunctionsModeling>();
 }
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 f4e3454f905b5..3f2051f53930d 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
@@ -143,32 +143,10 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t) {
 
 #endif // __has_feature(cxx_decltype)
 
-// __uninitialized_construct_buf_dispatch::__ucr is used by stable_sort
-// and inplace_merge.
-template<typename _Tp>
-struct __uninitialized_construct_buf_dispatch {
-  template<typename _ForwardIterator, typename _Allocator>
-  static void __ucr(_ForwardIterator __first, _ForwardIterator __last,
-                    _Allocator& __a) {
-    // Fake error trigger
-    int z = 0;
-    z = 5/z;
-  }
-};
-
 template<typename _RandomAccessIterator>
-void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
-  allocator<int> alloc;
-  __uninitialized_construct_buf_dispatch<int>::__ucr(__first, __last, alloc);
-}
-
-template<typename _BidirectionalIterator>
-void inplace_merge(_BidirectionalIterator __first,
-                   _BidirectionalIterator,
-                   _BidirectionalIterator __last) {
-  allocator<int> alloc;
-  __uninitialized_construct_buf_dispatch<int>::__ucr(__first, __last, alloc);
-}
+void sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {}
 
+template<typename _RandomAccessIterator>
+void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) 
{}
 }
 
diff --git a/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp 
b/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
index f49d6f78c165a..a54508ee9d6c5 100644
--- a/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
+++ b/clang/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
@@ -38,12 +38,12 @@ void testSuppression_std_shared_pointer() {
   p = nullptr; // no-warning
 }
 
-void testSuppression_stable_sort() {
+void testSuppression_sort() {
   int arr[5];
-  std::stable_sort(arr, arr + 5); // no-warning
+  std::sort(arr, arr + 5); // no-warning
 }
 
-void testSuppression_inplace_merge() {
+void testSuppression_stable_sort() {
   int arr[5];
-  std::inplace_merge(arr, arr + 2, arr + 5); // no-warning
+  std::stable_sort(arr, arr + 5); // no-warning
 }
diff --git 
a/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp 
b/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp
index bab43b0622b8d..c14a4583780c6 100644
--- a/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp
+++ b/clang/test/Analysis/diagnostics/opaque-stl-functions-modeling-tag.cpp
@@ -6,9 +6,9 @@
 
 void testOpaqueSTLTags() {
   int arr[5];
-  std::stable_sort(arr, arr + 5);
+  std::sort(arr, arr + 5);
 // CHECK: \"tag\": \"cplusplus.OpaqueSTLFunctionsModeling : Forced Opaque 
Call\"
-  std::inplace_merge(arr, arr + 2, arr + 5);
+  std::stable_sort(arr, arr + 5);
 // CHECK: \"tag\": \"cplusplus.OpaqueSTLFunctionsModeling : Forced Opaque 
Call\"
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to