109 lines
4.0 KiB
C++
109 lines
4.0 KiB
C++
//===--------------------------------------------------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "NoOwnershipChangeVisitor.h"
|
|
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
|
|
#include "llvm/ADT/SetOperations.h"
|
|
|
|
using namespace clang;
|
|
using namespace ento;
|
|
using OwnerSet = NoOwnershipChangeVisitor::OwnerSet;
|
|
|
|
namespace {
|
|
// Collect which entities point to the allocated memory, and could be
|
|
// responsible for deallocating it.
|
|
class OwnershipBindingsHandler : public StoreManager::BindingsHandler {
|
|
SymbolRef Sym;
|
|
OwnerSet &Owners;
|
|
|
|
public:
|
|
OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners)
|
|
: Sym(Sym), Owners(Owners) {}
|
|
|
|
bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region,
|
|
SVal Val) override {
|
|
if (Val.getAsSymbol() == Sym)
|
|
Owners.insert(Region);
|
|
return true;
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
|
|
LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const {
|
|
out << "Owners: {\n";
|
|
for (const MemRegion *Owner : Owners) {
|
|
out << " ";
|
|
Owner->dumpToStream(out);
|
|
out << ",\n";
|
|
}
|
|
out << "}\n";
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
OwnerSet NoOwnershipChangeVisitor::getOwnersAtNode(const ExplodedNode *N) {
|
|
OwnerSet Ret;
|
|
|
|
ProgramStateRef State = N->getState();
|
|
OwnershipBindingsHandler Handler{Sym, Ret};
|
|
State->getStateManager().getStoreManager().iterBindings(State->getStore(),
|
|
Handler);
|
|
return Ret;
|
|
}
|
|
|
|
LLVM_DUMP_METHOD std::string
|
|
NoOwnershipChangeVisitor::getFunctionName(const ExplodedNode *CallEnterN) {
|
|
if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
|
|
CallEnterN->getLocationAs<CallEnter>()->getCallExpr()))
|
|
if (const FunctionDecl *FD = CE->getDirectCallee())
|
|
return FD->getQualifiedNameAsString();
|
|
return "";
|
|
}
|
|
|
|
bool NoOwnershipChangeVisitor::wasModifiedInFunction(
|
|
const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN) {
|
|
const Decl *Callee =
|
|
CallExitEndN->getFirstPred()->getLocationContext()->getDecl();
|
|
if (!doesFnIntendToHandleOwnership(
|
|
Callee,
|
|
CallExitEndN->getState()->getAnalysisManager().getASTContext()))
|
|
return true;
|
|
|
|
if (hasResourceStateChanged(CallEnterN->getState(), CallExitEndN->getState()))
|
|
return true;
|
|
|
|
OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
|
|
OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
|
|
|
|
// Owners in the current set may be purged from the analyzer later on.
|
|
// If a variable is dead (is not referenced directly or indirectly after
|
|
// some point), it will be removed from the Store before the end of its
|
|
// actual lifetime.
|
|
// This means that if the ownership status didn't change, CurrOwners
|
|
// must be a superset of, but not necessarily equal to ExitOwners.
|
|
return !llvm::set_is_subset(ExitOwners, CurrOwners);
|
|
}
|
|
|
|
PathDiagnosticPieceRef NoOwnershipChangeVisitor::maybeEmitNoteForParameters(
|
|
PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) {
|
|
// TODO: Factor the logic of "what constitutes as an entity being passed
|
|
// into a function call" out by reusing the code in
|
|
// NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating
|
|
// the printing technology in UninitializedObject's FieldChainInfo.
|
|
ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
|
|
for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
|
|
SVal V = Call.getArgSVal(I);
|
|
if (V.getAsSymbol() == Sym)
|
|
return emitNote(N);
|
|
}
|
|
return nullptr;
|
|
}
|