diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 9e7c98fdded17..86774ad5043dd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -100,41 +100,7 @@ class SymbolConjured : public SymbolData { ConstCFGElementRef getCFGElementRef() const { return Elem; } // It might return null. - const Stmt *getStmt() const { - switch (Elem->getKind()) { - case CFGElement::Initializer: - return Elem->castAs().getInitializer()->getInit(); - case CFGElement::ScopeBegin: - return Elem->castAs().getTriggerStmt(); - case CFGElement::ScopeEnd: - return Elem->castAs().getTriggerStmt(); - case CFGElement::NewAllocator: - return Elem->castAs().getAllocatorExpr(); - case CFGElement::LifetimeEnds: - return Elem->castAs().getTriggerStmt(); - case CFGElement::LoopExit: - return Elem->castAs().getLoopStmt(); - case CFGElement::Statement: - return Elem->castAs().getStmt(); - case CFGElement::Constructor: - return Elem->castAs().getStmt(); - case CFGElement::CXXRecordTypedCall: - return Elem->castAs().getStmt(); - case CFGElement::AutomaticObjectDtor: - return Elem->castAs().getTriggerStmt(); - case CFGElement::DeleteDtor: - return Elem->castAs().getDeleteExpr(); - case CFGElement::BaseDtor: - return nullptr; - case CFGElement::MemberDtor: - return nullptr; - case CFGElement::TemporaryDtor: - return Elem->castAs().getBindTemporaryExpr(); - case CFGElement::CleanupFunction: - return nullptr; - } - return nullptr; - } + const Stmt *getStmt() const; unsigned getCount() const { return Count; } /// It might return null. diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index a6ade661d04a2..a469df4ca7160 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -80,6 +80,49 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const { os << ')'; } +const Stmt *SymbolConjured::getStmt() const { + // Sometimes the CFG element is invalid, avoid dereferencing it. + if (Elem.getParent() == nullptr || + Elem.getIndexInBlock() >= Elem.getParent()->size()) + return nullptr; + switch (Elem->getKind()) { + case CFGElement::Initializer: + if (const auto *Init = Elem->castAs().getInitializer()) { + return Init->getInit(); + } + return nullptr; + case CFGElement::ScopeBegin: + return Elem->castAs().getTriggerStmt(); + case CFGElement::ScopeEnd: + return Elem->castAs().getTriggerStmt(); + case CFGElement::NewAllocator: + return Elem->castAs().getAllocatorExpr(); + case CFGElement::LifetimeEnds: + return Elem->castAs().getTriggerStmt(); + case CFGElement::LoopExit: + return Elem->castAs().getLoopStmt(); + case CFGElement::Statement: + return Elem->castAs().getStmt(); + case CFGElement::Constructor: + return Elem->castAs().getStmt(); + case CFGElement::CXXRecordTypedCall: + return Elem->castAs().getStmt(); + case CFGElement::AutomaticObjectDtor: + return Elem->castAs().getTriggerStmt(); + case CFGElement::DeleteDtor: + return Elem->castAs().getDeleteExpr(); + case CFGElement::BaseDtor: + return nullptr; + case CFGElement::MemberDtor: + return nullptr; + case CFGElement::TemporaryDtor: + return Elem->castAs().getBindTemporaryExpr(); + case CFGElement::CleanupFunction: + return nullptr; + } + return nullptr; +} + void SymbolConjured::dumpToStream(raw_ostream &os) const { os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID(); if (auto *S = getStmt()) diff --git a/clang/test/Analysis/ftime-trace-no-init.cpp b/clang/test/Analysis/ftime-trace-no-init.cpp new file mode 100644 index 0000000000000..7fb289b19da78 --- /dev/null +++ b/clang/test/Analysis/ftime-trace-no-init.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling %s -ftime-trace=%t.raw.json -verify +// expected-no-diagnostics + +// GitHub issue 139779 +struct {} a; // no-crash