Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[analyzer] PR41269: Add a bit of C++ smart pointer modeling.
Implement cplusplus.SmartPtrModeling, a new checker that doesn't emit any warnings but models methods of smart pointers more precisely. For now the only thing it does is make `(bool) P` return false when `P` is a freshly moved pointer. This addresses a false positive in the use-after-move-checker. Differential Revision: https://reviews.llvm.org/D60796 llvm-svn: 358944
- Loading branch information
Showing
8 changed files
with
160 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//=== Move.h - Tracking moved-from objects. ------------------------*- C++ -*-// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Defines inter-checker API for the use-after-move checker. It allows | ||
// dependent checkers to figure out if an object is in a moved-from state. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H | ||
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H | ||
|
||
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" | ||
|
||
namespace clang { | ||
namespace ento { | ||
namespace move { | ||
|
||
/// Returns true if the object is known to have been recently std::moved. | ||
bool isMovedFrom(ProgramStateRef State, const MemRegion *Region); | ||
|
||
} // namespace move | ||
} // namespace ento | ||
} // namespace clang | ||
|
||
#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SmartPtrModeling.cpp - Model behavior of C++ smart pointers - C++ ------===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines a checker that models various aspects of | ||
// C++ smart pointer behavior. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "Move.h" | ||
|
||
#include "clang/AST/ExprCXX.h" | ||
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" | ||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | ||
#include "clang/StaticAnalyzer/Core/Checker.h" | ||
#include "clang/StaticAnalyzer/Core/CheckerManager.h" | ||
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | ||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | ||
|
||
using namespace clang; | ||
using namespace ento; | ||
|
||
namespace { | ||
class SmartPtrModeling : public Checker<eval::Call> { | ||
bool isNullAfterMoveMethod(const CXXInstanceCall *Call) const; | ||
|
||
public: | ||
bool evalCall(const CallExpr *CE, CheckerContext &C) const; | ||
}; | ||
} // end of anonymous namespace | ||
|
||
bool SmartPtrModeling::isNullAfterMoveMethod( | ||
const CXXInstanceCall *Call) const { | ||
// TODO: Update CallDescription to support anonymous calls? | ||
// TODO: Handle other methods, such as .get() or .release(). | ||
// But once we do, we'd need a visitor to explain null dereferences | ||
// that are found via such modeling. | ||
const auto *CD = dyn_cast<CXXConversionDecl>(Call->getDecl()); | ||
return CD && CD->getConversionType()->isBooleanType(); | ||
} | ||
|
||
bool SmartPtrModeling::evalCall(const CallExpr *CE, CheckerContext &C) const { | ||
CallEventRef<> CallRef = C.getStateManager().getCallEventManager().getCall( | ||
CE, C.getState(), C.getLocationContext()); | ||
const auto *Call = dyn_cast_or_null<CXXInstanceCall>(CallRef); | ||
if (!Call || !isNullAfterMoveMethod(Call)) | ||
return false; | ||
|
||
ProgramStateRef State = C.getState(); | ||
const MemRegion *ThisR = Call->getCXXThisVal().getAsRegion(); | ||
|
||
if (!move::isMovedFrom(State, ThisR)) { | ||
// TODO: Model this case as well. At least, avoid invalidation of globals. | ||
return false; | ||
} | ||
|
||
// TODO: Add a note to bug reports describing this decision. | ||
C.addTransition( | ||
State->BindExpr(CE, C.getLocationContext(), | ||
C.getSValBuilder().makeZeroVal(CE->getType()))); | ||
return true; | ||
} | ||
|
||
void ento::registerSmartPtrModeling(CheckerManager &Mgr) { | ||
Mgr.registerChecker<SmartPtrModeling>(); | ||
} | ||
|
||
bool ento::shouldRegisterSmartPtrModeling(const LangOptions &LO) { | ||
return LO.CPlusPlus; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\ | ||
// RUN: -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\ | ||
// RUN: -std=c++11 -verify %s | ||
|
||
#include "Inputs/system-header-simulator-cxx.h" | ||
|
||
void clang_analyzer_warnIfReached(); | ||
|
||
void derefAfterMove(std::unique_ptr<int> P) { | ||
std::unique_ptr<int> Q = std::move(P); | ||
if (Q) | ||
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | ||
*Q.get() = 1; // no-warning | ||
if (P) | ||
clang_analyzer_warnIfReached(); // no-warning | ||
// TODO: Report a null dereference (instead). | ||
*P.get() = 1; // expected-warning {{Method called on moved-from object 'P'}} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters