Skip to content

[analyzer] Add std::variant checker #66481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ def C11LockChecker : Checker<"C11Lock">,
Dependencies<[PthreadLockBase]>,
Documentation<HasDocumentation>;

def StdVariantChecker : Checker<"StdVariant">,
HelpText<"Check for bad type access for std::variant.">,
Documentation<HasDocumentation>;

} // end "alpha.core"

//===----------------------------------------------------------------------===//
Expand Down
99 changes: 50 additions & 49 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ enum CallEventKind {

class CallEvent;

template<typename T = CallEvent>
template <typename T = CallEvent>
class CallEventRef : public IntrusiveRefCntPtr<const T> {
public:
CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {}
Expand All @@ -94,8 +94,7 @@ class CallEventRef : public IntrusiveRefCntPtr<const T> {

// Allow implicit conversions to a superclass type, since CallEventRef
// behaves like a pointer-to-const.
template <typename SuperT>
operator CallEventRef<SuperT> () const {
template <typename SuperT> operator CallEventRef<SuperT>() const {
return this->get();
}
};
Expand Down Expand Up @@ -124,9 +123,9 @@ class RuntimeDefinition {

public:
RuntimeDefinition() = default;
RuntimeDefinition(const Decl *InD): D(InD) {}
RuntimeDefinition(const Decl *InD) : D(InD) {}
RuntimeDefinition(const Decl *InD, bool Foreign) : D(InD), Foreign(Foreign) {}
RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
RuntimeDefinition(const Decl *InD, const MemRegion *InR) : D(InD), R(InR) {}

const Decl *getDecl() { return D; }
bool isForeign() const { return Foreign; }
Expand Down Expand Up @@ -207,8 +206,9 @@ class CallEvent {

/// Used to specify non-argument regions that will be invalidated as a
/// result of this call.
virtual void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const {}
virtual void
getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const {}

public:
CallEvent &operator=(const CallEvent &) = delete;
Expand All @@ -231,14 +231,10 @@ class CallEvent {
void setForeign(bool B) const { Foreign = B; }

/// The state in which the call is being evaluated.
const ProgramStateRef &getState() const {
return State;
}
const ProgramStateRef &getState() const { return State; }

/// The context in which the call is being evaluated.
const LocationContext *getLocationContext() const {
return LCtx;
}
const LocationContext *getLocationContext() const { return LCtx; }

const CFGBlock::ConstCFGElementRef &getCFGElementRef() const {
return ElemRef;
Expand Down Expand Up @@ -270,7 +266,7 @@ class CallEvent {
SourceLocation Loc = D->getLocation();
if (Loc.isValid()) {
const SourceManager &SM =
getState()->getStateManager().getContext().getSourceManager();
getState()->getStateManager().getContext().getSourceManager();
return SM.isInSystemHeader(D->getLocation());
}

Expand Down Expand Up @@ -324,9 +320,7 @@ class CallEvent {
// NOTE: The exact semantics of this are still being defined!
// We don't really want a list of hardcoded exceptions in the long run,
// but we don't want duplicated lists of known APIs in the short term either.
virtual bool argumentsMayEscape() const {
return hasNonZeroCallbackArg();
}
virtual bool argumentsMayEscape() const { return hasNonZeroCallbackArg(); }

/// Returns true if the callee is an externally-visible function in the
/// top-level namespace, such as \c malloc.
Expand Down Expand Up @@ -456,6 +450,14 @@ class CallEvent {
/// can be retrieved from its construction context.
std::optional<SVal> getReturnValueUnderConstruction() const;

// Returns the CallEvent representing the caller of this function
const CallEventRef<> getCaller() const;

// Returns true if the function was called from a standard library function.
// If not or could not get the caller (it may be a top level function)
// returns false.
bool isCalledFromSystemHeader() const;

// Iterator access to formal parameters and their types.
private:
struct GetTypeFn {
Expand Down Expand Up @@ -579,8 +581,9 @@ class BlockCall : public CallEvent {

void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }

void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;
void getExtraInvalidatedValues(
ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;

public:
const CallExpr *getOriginExpr() const override {
Expand Down Expand Up @@ -650,14 +653,12 @@ class BlockCall : public CallEvent {
// the block body and analyze the operator() method on the captured lambda.
const VarDecl *LambdaVD = getRegionStoringCapturedLambda()->getDecl();
const CXXRecordDecl *LambdaDecl = LambdaVD->getType()->getAsCXXRecordDecl();
CXXMethodDecl* LambdaCallOperator = LambdaDecl->getLambdaCallOperator();
CXXMethodDecl *LambdaCallOperator = LambdaDecl->getLambdaCallOperator();

return RuntimeDefinition(LambdaCallOperator);
}

bool argumentsMayEscape() const override {
return true;
}
bool argumentsMayEscape() const override { return true; }

void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const override;
Expand All @@ -684,8 +685,9 @@ class CXXInstanceCall : public AnyFunctionCall {
: AnyFunctionCall(D, St, LCtx, ElemRef) {}
CXXInstanceCall(const CXXInstanceCall &Other) = default;

void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;
void getExtraInvalidatedValues(
ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;

public:
/// Returns the expression representing the implicit 'this' object.
Expand Down Expand Up @@ -843,7 +845,9 @@ class CXXDestructorCall : public CXXInstanceCall {

CXXDestructorCall(const CXXDestructorCall &Other) = default;

void cloneTo(void *Dest) const override {new (Dest) CXXDestructorCall(*this);}
void cloneTo(void *Dest) const override {
new (Dest) CXXDestructorCall(*this);
}

public:
SourceRange getSourceRange() const override { return Location; }
Expand Down Expand Up @@ -880,8 +884,9 @@ class AnyCXXConstructorCall : public AnyFunctionCall {
Data = Target;
}

void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;
void getExtraInvalidatedValues(
ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;

void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const override;
Expand Down Expand Up @@ -921,7 +926,9 @@ class CXXConstructorCall : public AnyCXXConstructorCall {

CXXConstructorCall(const CXXConstructorCall &Other) = default;

void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); }
void cloneTo(void *Dest) const override {
new (Dest) CXXConstructorCall(*this);
}

public:
const CXXConstructExpr *getOriginExpr() const override {
Expand Down Expand Up @@ -1040,7 +1047,9 @@ class CXXAllocatorCall : public AnyFunctionCall {
: AnyFunctionCall(E, St, LCtx, ElemRef) {}
CXXAllocatorCall(const CXXAllocatorCall &Other) = default;

void cloneTo(void *Dest) const override { new (Dest) CXXAllocatorCall(*this); }
void cloneTo(void *Dest) const override {
new (Dest) CXXAllocatorCall(*this);
}

public:
const CXXNewExpr *getOriginExpr() const override {
Expand Down Expand Up @@ -1154,11 +1163,7 @@ class CXXDeallocatorCall : public AnyFunctionCall {
//
// Note to maintainers: OCM_Message should always be last, since it does not
// need to fit in the Data field's low bits.
enum ObjCMessageKind {
OCM_PropertyAccess,
OCM_Subscript,
OCM_Message
};
enum ObjCMessageKind { OCM_PropertyAccess, OCM_Subscript, OCM_Message };

/// Represents any expression that calls an Objective-C method.
///
Expand All @@ -1180,8 +1185,9 @@ class ObjCMethodCall : public CallEvent {

void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); }

void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;
void getExtraInvalidatedValues(
ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const override;

/// Check if the selector may have multiple definitions (may have overrides).
virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
Expand All @@ -1196,9 +1202,7 @@ class ObjCMethodCall : public CallEvent {
return getOriginExpr()->getMethodDecl();
}

unsigned getNumArgs() const override {
return getOriginExpr()->getNumArgs();
}
unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); }

const Expr *getArgExpr(unsigned Index) const override {
return getOriginExpr()->getArg(Index);
Expand All @@ -1212,9 +1216,7 @@ class ObjCMethodCall : public CallEvent {
return getOriginExpr()->getMethodFamily();
}

Selector getSelector() const {
return getOriginExpr()->getSelector();
}
Selector getSelector() const { return getOriginExpr()->getSelector(); }

SourceRange getSourceRange() const override;

Expand Down Expand Up @@ -1262,7 +1264,7 @@ class ObjCMethodCall : public CallEvent {
void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const override;

ArrayRef<ParmVarDecl*> parameters() const override;
ArrayRef<ParmVarDecl *> parameters() const override;

Kind getKind() const override { return CE_ObjCMessage; }
StringRef getKindAsString() const override { return "ObjCMethodCall"; }
Expand Down Expand Up @@ -1336,8 +1338,8 @@ class CallEventManager {
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}

/// Gets an outside caller given a callee context.
CallEventRef<>
getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
CallEventRef<> getCaller(const StackFrameContext *CalleeCtx,
ProgramStateRef State);

/// Gets a call event for a function call, Objective-C method call,
/// a 'new', or a 'delete' call.
Expand Down Expand Up @@ -1433,11 +1435,10 @@ inline void CallEvent::Release() const {
namespace llvm {

// Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
template<class T> struct simplify_type< clang::ento::CallEventRef<T>> {
template <class T> struct simplify_type<clang::ento::CallEventRef<T>> {
using SimpleType = const T *;

static SimpleType
getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
static SimpleType getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
return Val.get();
}
};
Expand Down
1 change: 1 addition & 0 deletions clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ add_clang_library(clangStaticAnalyzerCheckers
SmartPtrModeling.cpp
StackAddrEscapeChecker.cpp
StdLibraryFunctionsChecker.cpp
StdVariantChecker.cpp
STLAlgorithmModeling.cpp
StreamChecker.cpp
StringChecker.cpp
Expand Down
Loading