class NoStateChangeFuncVisitor

Declaration

class NoStateChangeFuncVisitor : public BugReporterVisitor { /* full declaration omitted */ };

Description

Put a diagnostic on return statement (or on } in its absence) of all inlined functions for which some property remained unchanged. Resulting diagnostics may read such as "Returning without writing to X". Descendants can define what a "state change is", like a change of value to a memory region, liveness, etc. For function calls where the state did not change as defined, a custom note may be constructed. For a minimal example, check out clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:639

Inherits from: BugReporterVisitor

Member Variables

private llvm::SmallPtrSet<const StackFrameContext*, 32> FramesModifying
Frames modifying the state as defined in \c wasModifiedBeforeCallExit. This visitor generates a note only if a function does *not* change the state that way. This information is not immediately available by looking at the node associated with the exit from the function (usually the return statement). To avoid recomputing the same information many times (going up the path for each node and checking whether the region was written into) we instead lazily compute the stack frames along the path.
private llvm::SmallPtrSet<const StackFrameContext*, 32> FramesModifyingCalculated
protected bugreporter::TrackingKind TKind

Method Overview

  • public NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind)
  • public clang::ento::PathDiagnosticPieceRef VisitNode(const clang::ento::ExplodedNode * N, clang::ento::BugReporterContext & BR, clang::ento::PathSensitiveBugReport & R)
  • private void findModifyingFrames(const clang::ento::ExplodedNode *const CallExitBeginN)
  • private bool isModifiedInFrame(const clang::ento::ExplodedNode * CallExitBeginN)
  • private void markFrameAsModifying(const clang::StackFrameContext * SCtx)
  • protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForCXXThis(clang::ento::PathSensitiveBugReport & R, const clang::ento::CXXConstructorCall & Call, const clang::ento::ExplodedNode * N)
  • protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(clang::ento::PathSensitiveBugReport & R, const clang::ento::ObjCMethodCall & Call, const clang::ento::ExplodedNode * N)
  • protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForParameters(clang::ento::PathSensitiveBugReport & R, const clang::ento::CallEvent & Call, const clang::ento::ExplodedNode * N)
  • protected virtual bool wasModifiedBeforeCallExit(const clang::ento::ExplodedNode * CurrN, const clang::ento::ExplodedNode * CallExitBeginN)
  • protected virtual bool wasModifiedInFunction(const clang::ento::ExplodedNode * CallEnterN, const clang::ento::ExplodedNode * CallExitEndN)

Inherited from BugReporterVisitor:

Inherited from FoldingSetBase::Node:

Methods

NoStateChangeFuncVisitor(
    bugreporter::TrackingKind TKind)

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:730

Parameters

bugreporter::TrackingKind TKind

clang::ento::PathDiagnosticPieceRef VisitNode(
    const clang::ento::ExplodedNode* N,
    clang::ento::BugReporterContext& BR,
    clang::ento::PathSensitiveBugReport& R)

Description

Return a diagnostic piece which should be associated with the given node. Note that this function does *not* get run on the very last node of the report, as the PathDiagnosticPiece associated with the last node should be unique. Use \ref getEndPath to customize the note associated with the report end instead. The last parameter can be used to register a new visitor with the given BugReport while processing a node.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:732

Parameters

const clang::ento::ExplodedNode* N
clang::ento::BugReporterContext& BR
clang::ento::PathSensitiveBugReport& R

void findModifyingFrames(
    const clang::ento::ExplodedNode* const
        CallExitBeginN)

Description

Write to \c FramesModifying all stack frames along the path in the current stack frame which modifies the state.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:663

Parameters

const clang::ento::ExplodedNode* const CallExitBeginN

bool isModifiedInFrame(
    const clang::ento::ExplodedNode*
        CallExitBeginN)

Description

Check and lazily calculate whether the state is modified in the stack frame to which \p CallExitBeginN belongs. The calculation is cached in FramesModifying.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:657

Parameters

const clang::ento::ExplodedNode* CallExitBeginN

void markFrameAsModifying(
    const clang::StackFrameContext* SCtx)

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:659

Parameters

const clang::StackFrameContext* SCtx

virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(
    clang::ento::PathSensitiveBugReport& R,
    const clang::ento::CXXConstructorCall& Call,
    const clang::ento::ExplodedNode* N)

Description

Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:716

Parameters

clang::ento::PathSensitiveBugReport& R
const clang::ento::CXXConstructorCall& Call
const clang::ento::ExplodedNode* N

Returns

Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".

virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(
    clang::ento::PathSensitiveBugReport& R,
    const clang::ento::ObjCMethodCall& Call,
    const clang::ento::ExplodedNode* N)

Description

Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:706

Parameters

clang::ento::PathSensitiveBugReport& R
const clang::ento::ObjCMethodCall& Call
const clang::ento::ExplodedNode* N

Returns

Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".

virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForParameters(
    clang::ento::PathSensitiveBugReport& R,
    const clang::ento::CallEvent& Call,
    const clang::ento::ExplodedNode* N)

Description

Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:726

Parameters

clang::ento::PathSensitiveBugReport& R
const clang::ento::CallEvent& Call
const clang::ento::ExplodedNode* N

Returns

Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".

virtual bool wasModifiedBeforeCallExit(
    const clang::ento::ExplodedNode* CurrN,
    const clang::ento::ExplodedNode*
        CallExitBeginN)

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:677

Parameters

const clang::ento::ExplodedNode* CurrN
const clang::ento::ExplodedNode* CallExitBeginN

Returns

Whether the state was modified from the current node, \p CurrN, to the end of the stack frame, at \p CallExitBeginN. \p CurrN and\p CallExitBeginN are always in the same stack frame. Clients should override this callback when a state change is important not only on the entire function call, but inside of it as well. Example: we may want to leave a note about the lack of locking/unlocking on a particular mutex, but not if inside the function its state was changed, but also restored. wasModifiedInFunction() wouldn't know of this change.

virtual bool wasModifiedInFunction(
    const clang::ento::ExplodedNode* CallEnterN,
    const clang::ento::ExplodedNode* CallExitEndN)

Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:695

Parameters

const clang::ento::ExplodedNode* CallEnterN
const clang::ento::ExplodedNode* CallExitEndN

Returns

Whether the state was modified in the inlined function call in between \p CallEnterN and \p CallExitEndN. Mind that the stack frame retrieved from a CallEnterN and CallExitEndN is the *caller's* stack frame! The inlined function's stack should be retrieved from either the immediate successor to \p CallEnterN or immediate predecessor to\p CallExitEndN. Clients should override this function if a state changes local to the inlined function are not interesting, only the change occuring as a result of it. Example: we want to leave a not about a leaked resource object not being deallocated / its ownership changed inside a function, and we don't care if it was assigned to a local variable (its change in ownership is inconsequential).