Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang-tidy] bugprone-unchecked-optional-access stuck at 100% sometimes #59492

Closed
ArnaudBienner opened this issue Dec 13, 2022 · 12 comments
Closed
Labels
clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang-tidy

Comments

@ArnaudBienner
Copy link
Contributor

ArnaudBienner commented Dec 13, 2022

Hi,

This doesn't happen at every run, but very often clang-tidy will get stuck when analyzing my project (not open source so I can't share it here, and didn't manage yet to narrow it down to a small example which reproduces the issue).

This happens more often (but not only) when bugprone-unchecked-optional-access is activated.

Tried both clang-tidy-15 and latest clang-tidy built from git (commit bbcffb0) and had the issue.

Stack trace:

0x0000aaaad50dcd2c in clang::dataflow::WatchedLiteralsSolverImpl::solve() && ()
(gdb) bt
#0  0x0000aaaad50dcd2c in clang::dataflow::WatchedLiteralsSolverImpl::solve() && ()
#1  0x0000aaaad50dff94 in clang::dataflow::WatchedLiteralsSolver::solve(llvm::DenseSet<clang::dataflow::BoolValue*, llvm::DenseMapInfo<clang::dataflow::BoolValue*, void> >) ()
#2  0x0000aaaad50ca1e0 in clang::dataflow::DataflowAnalysisContext::querySolver(llvm::DenseSet<clang::dataflow::BoolValue*, llvm::DenseMapInfo<clang::dataflow::BoolValue*, void> >) ()
#3  0x0000aaaad50ca43c in clang::dataflow::DataflowAnalysisContext::flowConditionImplies(clang::dataflow::AtomicBoolValue&, clang::dataflow::BoolValue&) ()
#4  0x0000aaaad50bd20c in clang::dataflow::UncheckedOptionalAccessModel::merge(clang::QualType, clang::dataflow::Value const&, clang::dataflow::Environment const&, clang::dataflow::Value const&, clang::dataflow::Environment const&, clang::dataflow::Value&, clang::dataflow::Environment&) ()
#5  0x0000aaaad50d5a94 in clang::dataflow::Environment::join(clang::dataflow::Environment const&, clang::dataflow::Environment::ValueModel&) ()
#6  0x0000aaaad50d8750 in clang::dataflow::computeBlockInputState(clang::CFGBlock const&, clang::dataflow::AnalysisContext&) ()
#7  0x0000aaaad50d9480 in clang::dataflow::transferCFGBlock(clang::CFGBlock const&, clang::dataflow::AnalysisContext&, std::function<void (clang::CFGElement const&, clang::dataflow::TypeErasedDataflowAnalysisState const&)>) ()
#8  0x0000aaaad50da070 in clang::dataflow::runTypeErasedDataflowAnalysis(clang::dataflow::ControlFlowContext const&, clang::dataflow::TypeErasedDataflowAnalysis&, clang::dataflow::Environment const&, std::function<void (clang::CFGElement const&, clang::dataflow::TypeErasedDataflowAnalysisState const&)>) ()
#9  0x0000aaaad424dd98 in llvm::Expected<std::vector<llvm::Optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::UncheckedOptionalAccessModel::Lattice> >, std::allocator<llvm::Optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::UncheckedOptionalAccessModel::Lattice> > > > > clang::dataflow::runDataflowAnalysis<clang::dataflow::UncheckedOptionalAccessModel>(clang::dataflow::ControlFlowContext const&, clang::dataflow::UncheckedOptionalAccessModel&, clang::dataflow::Environment const&, std::function<void (clang::CFGElement const&, clang::dataflow::DataflowAnalysisState<clang::dataflow::UncheckedOptionalAccessModel::Lattice> const&)>) ()
#10 0x0000aaaad424e654 in clang::tidy::bugprone::analyzeFunction(clang::FunctionDecl const&, clang::ASTContext&) ()
#11 0x0000aaaad424e92c in clang::tidy::bugprone::UncheckedOptionalAccessCheck::check(clang::ast_matchers::MatchFinder::MatchResult const&) ()
#12 0x0000aaaad689e870 in clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor::MatchVisitor::visitMatch(clang::ast_matchers::BoundNodes const&) ()
#13 0x0000aaaad68ef3f8 in clang::ast_matchers::internal::BoundNodesTreeBuilder::visitMatches(clang::ast_matchers::internal::BoundNodesTreeBuilder::Visitor*) ()
#14 0x0000aaaad68a0e88 in clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor::matchWithFilter(clang::DynTypedNode const&) ()
#15 0x0000aaaad68c8f44 in clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor::TraverseDecl(clang::Decl*) ()
#16 0x0000aaaad68cb8f0 in clang::RecursiveASTVisitor<clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor>::TraverseDeclContextHelper(clang::DeclContext*) [clone .part.0] ()
#17 0x0000aaaad68e8138 in clang::RecursiveASTVisitor<clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor>::TraverseTranslationUnitDecl(clang::TranslationUnitDecl*) ()
#18 0x0000aaaad68c9024 in clang::ast_matchers::internal::(anonymous namespace)::MatchASTVisitor::TraverseDecl(clang::Decl*) ()
#19 0x0000aaaad68cb3c0 in clang::ast_matchers::MatchFinder::matchAST(clang::ASTContext&) ()
#20 0x0000aaaad59222cc in clang::MultiplexConsumer::HandleTranslationUnit(clang::ASTContext&) ()
#21 0x0000aaaad5b2d0a8 in clang::ParseAST(clang::Sema&, bool, bool) ()
#22 0x0000aaaad58f3d04 in clang::FrontendAction::Execute() ()
#23 0x0000aaaad5888d3c in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) ()
#24 0x0000aaaad515d950 in clang::tooling::FrontendActionFactory::runInvocation(std::shared_ptr<clang::CompilerInvocation>, clang::FileManager*, std::shared_ptr<clang::PCHContainerOperations>, clang::DiagnosticConsumer*) ()
#25 0x0000aaaad510ca70 in clang::tidy::runClangTidy(clang::tidy::ClangTidyContext&, clang::tooling::CompilationDatabase const&, llvm::ArrayRef<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, bool, bool, llvm::StringRef)::ActionFactory::runInvocation(std::shared_ptr<clang::CompilerInvocation>, clang::FileManager*, std::shared_ptr<clang::PCHContainerOperations>, clang::DiagnosticConsumer*) ()
#26 0x0000aaaad515603c in clang::tooling::ToolInvocation::runInvocation(char const*, clang::driver::Compilation*, std::shared_ptr<clang::CompilerInvocation>, std::shared_ptr<clang::PCHContainerOperations>) ()
#27 0x0000aaaad5159f40 in clang::tooling::ToolInvocation::run() ()
#28 0x0000aaaad515b6e0 in clang::tooling::ClangTool::run(clang::tooling::ToolAction*) ()
#29 0x0000aaaad51119dc in clang::tidy::runClangTidy(clang::tidy::ClangTidyContext&, clang::tooling::CompilationDatabase const&, llvm::ArrayRef<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, bool, bool, llvm::StringRef) ()
#30 0x0000aaaad40bc2a8 in clang::tidy::clangTidyMain(int, char const**) ()
#31 0x0000ffff977e1e10 in __libc_start_main (main=0xaaaad4079768 <main>, argc=58, argv=0xffffe933e1e8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=<optimized out>)
    at ../csu/libc-start.c:308
#32 0x0000aaaad40b55d0 in _start ()

Unfortunately, I don't have debug symbols as I didn't managed to build with debug symbols (build error because of relocation: I suspect with debug symbols object are too big for my system).

This issue looks similar to #55530.

@ArnaudBienner
Copy link
Contributor Author

I meant issue #55530

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 13, 2022

@llvm/issue-subscribers-clang-tidy

@tsteven4
Copy link

I can reproduce this in an open source project, and I have it isolated to a handful of lines.
It occurs with https://github.com/GPSBabel/gpsbabel/tree/70b64180144f2ccd69bdc3a311539c7112166ee9 and the file xcsv.cc.
It can be fixed by commenting out lines 499-505 and 509-515.
parse_data->lat_dir_positive, parse_date->lon_dir_positive are of type std::optional.

For me it seems to hang every time, and only occurs when bugprone-unchecked-optional-access is enabled.

@tsteven4
Copy link

I am running

.\clang-tidy.exe --version
LLVM (http://llvm.org/):
  LLVM version 15.0.2
  Optimized build.
  Default target: i686-pc-windows-msvc
  Host CPU: alderlake

@tsteven4
Copy link

I can also reproduce the hang on ubuntu kinetic. Again, commenting out the lines indicated above allows clang-tidy to complete in a timely manner.
docker run -it tsteven4/gpsbabel_build_environment_kinetic /bin/bash
and then execute

git clone https://github.com/GPSBabel/gpsbabel.git
cd gpsbabel
git checkout 70b64180144f2ccd69bdc3a311539c7112166ee9
mkdir bld
cd bld
cmake -G Ninja -DCMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu/cmake/Qt6 -DGPSBABEL_ENABLE_PCH=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
apt-get update
apt-get install -y --no-install-recommends clang-tidy
echo "starting clang-tidy"
clang-tidy --checks='-*,bugprone-unchecked-optional-access' ../xcsv.cc

The clang-tidy version info is

# clang-tidy --version
Ubuntu LLVM version 15.0.2

  Optimized build.
  Default target: x86_64-pc-linux-gnu
  Host CPU: alderlake
# apt list --installed clang-tidy
Listing... Done
clang-tidy/kinetic,now 1:15.0-55.1ubuntu1 amd64 [installed]

@tsteven4
Copy link

@nilssonk
Copy link

Sorry for the "me too," but we just hit this in our project after a PR which added a few more uses of std::optional to a fairly large file. There was also a false positive involving a ternary check, but I suppose it is unrelated to this issue.

It would be very nice if this was solved because the check is invaluable to us.

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"

$ clang --version
Ubuntu clang version 15.0.7
Target: x86_64-pc-linux-gnu
Thread model: posix

@PiotrZSL
Copy link
Member

Same problem visible on LLVM 17 with Cataclysm-DDA project on files: src/ui_manager.cpp, src/npcmove.cpp, src/monstergenerator.cpp. Currently this check is simply unusable, due to instability, simple bugs, and when checking github for this check looks like 87 projects decided simply to disable it.

@PiotrZSL PiotrZSL added the clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html label May 27, 2023
@R2RT
Copy link
Contributor

R2RT commented Oct 15, 2023

I've been hit by same problem lately. While working on repro, by chance I came up with code which is either processed under 1s, around 1 minute or stuck at least 1h [*] with single line change.

Checked on the latest LLVM release 17.0.2, with C++20, --checks "-*,bugprone-unchecked-optional-access".
Same result regardless of IgnoreSmartPointerDereference flag value.

I will check on the main branch once I get clang-tidy built.

Probably not relevant, but reproduces on all optional implementations (msvc, libstd++ and libc++).

#include <cstdlib>
#include <optional>
#include <vector>

std::optional<int> create(int);

void foo(std::vector<int> data)
{
  std::optional<int> opt;

  for(const auto &x: data) {
    opt = create(x);
    if(!opt.has_value()) {
      opt = create(x);
    }

    // ~60s processing by default

    if(rand() == 3) { continue; } // Comment for instant processing

    // bool y = *opt > 10; // Uncomment for "infinite" processing

    for(const auto &result: std::vector<int> {}) {} // Comment for instant processing
  }
}

[*] Timings on i7-770K Intel CPU. I will leave it running overnight.

@R2RT
Copy link
Contributor

R2RT commented Oct 15, 2023

Yay, good news, seems it is does no longer reproduce on main (tested on commit d5e91ca).
Neither on snippet above nor production code!

Upcoming LLVM 18 should have it fixed (?)

@ymand
Copy link
Collaborator

ymand commented Mar 7, 2024

Given @R2RT 's comments and the extensive performance improvements we've made to the framework and the entire rewriting of the core of the optional checker, I'm going to close this. If anyone else on this thread is still seeing reproducable behavior in recent releases, please reopen.

@ymand ymand closed this as completed Mar 7, 2024
@tsteven4
Copy link

tsteven4 commented Mar 7, 2024

I can confirm my testcase hangs on Ubuntu noble with clang-tidy 17.0.6, but completes with clang-tidy 18.1.0. However, it seems to flag a false positive:

# clang-tidy-18 --checks='-*,bugprone-unchecked-optional-access' ../xcsv.cc
2 warnings generated.
/app/gpsbabel/xcsv.cc:903:57: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
  903 |       if (parse_data.lat_dir_positive.has_value() && !(*parse_data.lat_dir_positive) && (wpt_tmp->latitude > 0.0)) {
      |                                                         ^
/app/gpsbabel/xcsv.cc:906:57: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
  906 |       if (parse_data.lon_dir_positive.has_value() && !(*parse_data.lon_dir_positive) && (wpt_tmp->longitude > 0.0)) {
      |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang-tidy
Projects
None yet
Development

No branches or pull requests

8 participants