|
@@ -239,6 +239,8 @@ public:
|
|
|
generate(const PathDiagnosticConsumer *PDC) const;
|
|
|
|
|
|
private:
|
|
|
+ void updateStackPiecesWithMessage(PathDiagnosticPieceRef P,
|
|
|
+ const CallWithEntryStack &CallStack) const;
|
|
|
void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,
|
|
|
PathDiagnosticLocation &PrevLoc) const;
|
|
|
|
|
@@ -269,6 +271,69 @@ private:
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+// Base implementation of stack hint generators.
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+StackHintGenerator::~StackHintGenerator() = default;
|
|
|
+
|
|
|
+std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
|
|
|
+ if (!N)
|
|
|
+ return getMessageForSymbolNotFound();
|
|
|
+
|
|
|
+ ProgramPoint P = N->getLocation();
|
|
|
+ CallExitEnd CExit = P.castAs<CallExitEnd>();
|
|
|
+
|
|
|
+ // FIXME: Use CallEvent to abstract this over all calls.
|
|
|
+ const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
|
|
|
+ const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
|
|
|
+ if (!CE)
|
|
|
+ return {};
|
|
|
+
|
|
|
+ // Check if one of the parameters are set to the interesting symbol.
|
|
|
+ unsigned ArgIndex = 0;
|
|
|
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(),
|
|
|
+ E = CE->arg_end(); I != E; ++I, ++ArgIndex){
|
|
|
+ SVal SV = N->getSVal(*I);
|
|
|
+
|
|
|
+ // Check if the variable corresponding to the symbol is passed by value.
|
|
|
+ SymbolRef AS = SV.getAsLocSymbol();
|
|
|
+ if (AS == Sym) {
|
|
|
+ return getMessageForArg(*I, ArgIndex);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if the parameter is a pointer to the symbol.
|
|
|
+ if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
|
|
|
+ // Do not attempt to dereference void*.
|
|
|
+ if ((*I)->getType()->isVoidPointerType())
|
|
|
+ continue;
|
|
|
+ SVal PSV = N->getState()->getSVal(Reg->getRegion());
|
|
|
+ SymbolRef AS = PSV.getAsLocSymbol();
|
|
|
+ if (AS == Sym) {
|
|
|
+ return getMessageForArg(*I, ArgIndex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if we are returning the interesting symbol.
|
|
|
+ SVal SV = N->getSVal(CE);
|
|
|
+ SymbolRef RetSym = SV.getAsLocSymbol();
|
|
|
+ if (RetSym == Sym) {
|
|
|
+ return getMessageForReturn(CE);
|
|
|
+ }
|
|
|
+
|
|
|
+ return getMessageForSymbolNotFound();
|
|
|
+}
|
|
|
+
|
|
|
+std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
|
|
|
+ unsigned ArgIndex) {
|
|
|
+ // Printed parameters start at 1, not 0.
|
|
|
+ ++ArgIndex;
|
|
|
+
|
|
|
+ return (llvm::Twine(Msg) + " via " + std::to_string(ArgIndex) +
|
|
|
+ llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();
|
|
|
+}
|
|
|
+
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
// Helper routines for walking the ExplodedGraph and fetching statements.
|
|
|
//===----------------------------------------------------------------------===//
|
|
@@ -661,7 +726,7 @@ getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
/// If the piece contains a special message, add it to all the call pieces on
|
|
|
-/// the active stack. For exampler, my_malloc allocated memory, so MallocChecker
|
|
|
+/// the active stack. For example, my_malloc allocated memory, so MallocChecker
|
|
|
/// will construct an event at the call to malloc(), and add a stack hint that
|
|
|
/// an allocated memory was returned. We'll use this hint to construct a message
|
|
|
/// when returning from the call to my_malloc
|
|
@@ -670,22 +735,20 @@ getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
|
|
|
/// void fishy() {
|
|
|
/// void *ptr = my_malloc(); // returned allocated memory
|
|
|
/// } // leak
|
|
|
-static void updateStackPiecesWithMessage(PathDiagnosticPiece &P,
|
|
|
- const CallWithEntryStack &CallStack) {
|
|
|
- if (auto *ep = dyn_cast<PathDiagnosticEventPiece>(&P)) {
|
|
|
- if (ep->hasCallStackHint())
|
|
|
- for (const auto &I : CallStack) {
|
|
|
- PathDiagnosticCallPiece *CP = I.first;
|
|
|
- const ExplodedNode *N = I.second;
|
|
|
- std::string stackMsg = ep->getCallStackMessage(N);
|
|
|
-
|
|
|
- // The last message on the path to final bug is the most important
|
|
|
- // one. Since we traverse the path backwards, do not add the message
|
|
|
- // if one has been previously added.
|
|
|
- if (!CP->hasCallStackMessage())
|
|
|
- CP->setCallStackMessage(stackMsg);
|
|
|
- }
|
|
|
- }
|
|
|
+void PathDiagnosticBuilder::updateStackPiecesWithMessage(
|
|
|
+ PathDiagnosticPieceRef P, const CallWithEntryStack &CallStack) const {
|
|
|
+ if (R->hasCallStackHint(P))
|
|
|
+ for (const auto &I : CallStack) {
|
|
|
+ PathDiagnosticCallPiece *CP = I.first;
|
|
|
+ const ExplodedNode *N = I.second;
|
|
|
+ std::string stackMsg = R->getCallStackMessage(P, N);
|
|
|
+
|
|
|
+ // The last message on the path to final bug is the most important
|
|
|
+ // one. Since we traverse the path backwards, do not add the message
|
|
|
+ // if one has been previously added.
|
|
|
+ if (!CP->hasCallStackMessage())
|
|
|
+ CP->setCallStackMessage(stackMsg);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void CompactMacroExpandedPieces(PathPieces &path,
|
|
@@ -1990,7 +2053,7 @@ PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
|
|
|
|
|
|
if (PDC->shouldAddPathEdges())
|
|
|
addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());
|
|
|
- updateStackPiecesWithMessage(*Note, Construct.CallStack);
|
|
|
+ updateStackPiecesWithMessage(Note, Construct.CallStack);
|
|
|
Construct.getActivePath().push_front(Note);
|
|
|
}
|
|
|
}
|