https://github.com/gamesh411 created https://github.com/llvm/llvm-project/pull/178910
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. 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] [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\" +} + _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
