Skip to content

Commit 81f5cfd

Browse files
committed
[clang][dataflow] Add test for crash repro and clean up const accessor handling
Add test for llvm#125589 The crash is actually incidentally fixed by llvm#128437 since it added a branch for the reference case and would no longer fall through when the return type is a reference to a pointer. Clean up a bit as well: - make the fallback for early returns more consistent (check if returning optional and call transfer function for that case) - check RecordLoc == nullptr in one place Add some init for the reference to pointer/bool cases.
1 parent ab811e7 commit 81f5cfd

File tree

2 files changed

+64
-30
lines changed

2 files changed

+64
-30
lines changed

clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -551,15 +551,17 @@ void transferCallReturningOptional(const CallExpr *E,
551551
setHasValue(*Loc, State.Env.makeAtomicBoolValue(), State.Env);
552552
}
553553

554-
void handleConstMemberCall(const CallExpr *CE,
554+
bool handleConstMemberCall(const CallExpr *CE,
555555
dataflow::RecordStorageLocation *RecordLoc,
556556
const MatchFinder::MatchResult &Result,
557557
LatticeTransferState &State) {
558+
if (RecordLoc == nullptr) return false;
559+
558560
// If the const method returns an optional or reference to an optional.
559-
if (RecordLoc != nullptr && isSupportedOptionalType(CE->getType())) {
561+
if (isSupportedOptionalType(CE->getType())) {
560562
const FunctionDecl *DirectCallee = CE->getDirectCallee();
561563
if (DirectCallee == nullptr)
562-
return;
564+
return false;
563565
StorageLocation &Loc =
564566
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
565567
*RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
@@ -577,57 +579,65 @@ void handleConstMemberCall(const CallExpr *CE,
577579
auto &ResultLoc = State.Env.getResultObjectLocation(*CE);
578580
copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
579581
}
580-
return;
582+
return true;
581583
}
582584

585+
bool IsBooleanOrPointer = CE->getType()->isBooleanType() ||
586+
CE->getType()->isPointerType();
587+
583588
// Cache if the const method returns a reference
584-
if (RecordLoc != nullptr && CE->isGLValue()) {
589+
if (CE->isGLValue()) {
585590
const FunctionDecl *DirectCallee = CE->getDirectCallee();
586591
if (DirectCallee == nullptr)
587-
return;
592+
return false;
588593

589594
StorageLocation &Loc =
590595
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
591596
*RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
592-
// no-op
597+
if (IsBooleanOrPointer) {
598+
State.Env.setValue(Loc, *State.Env.createValue(CE->getType()));
599+
}
593600
});
594601

595602
State.Env.setStorageLocation(*CE, Loc);
596-
return;
597-
}
598-
599-
// Cache if the const method returns a boolean or pointer type.
600-
// We may decide to cache other return types in the future.
601-
if (RecordLoc != nullptr &&
602-
(CE->getType()->isBooleanType() || CE->getType()->isPointerType())) {
603+
return true;
604+
} else if (IsBooleanOrPointer) {
605+
// Cache if the const method returns a boolean or pointer type.
603606
Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, CE,
604607
State.Env);
605608
if (Val == nullptr)
606-
return;
609+
return false;
607610
State.Env.setValue(*CE, *Val);
608-
return;
611+
return true;
609612
}
610613

611-
// Perform default handling if the call returns an optional
612-
// but wasn't handled above (if RecordLoc is nullptr).
613-
if (isSupportedOptionalType(CE->getType())) {
614-
transferCallReturningOptional(CE, Result, State);
615-
}
614+
return false;
616615
}
617616

618-
void transferValue_ConstMemberCall(const CXXMemberCallExpr *MCE,
619-
const MatchFinder::MatchResult &Result,
620-
LatticeTransferState &State) {
621-
handleConstMemberCall(
622-
MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result, State);
617+
void transferConstMemberCall(const CXXMemberCallExpr *MCE,
618+
const MatchFinder::MatchResult &Result,
619+
LatticeTransferState &State) {
620+
if (!handleConstMemberCall(
621+
MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result,
622+
State)) {
623+
// Perform default handling if the call returns an optional,
624+
// but wasn't handled.
625+
if (isSupportedOptionalType(MCE->getType()))
626+
transferCallReturningOptional(MCE, Result, State);
627+
}
623628
}
624629

625-
void transferValue_ConstMemberOperatorCall(
626-
const CXXOperatorCallExpr *OCE, const MatchFinder::MatchResult &Result,
627-
LatticeTransferState &State) {
630+
void transferConstMemberOperatorCall(const CXXOperatorCallExpr *OCE,
631+
const MatchFinder::MatchResult &Result,
632+
LatticeTransferState &State) {
628633
auto *RecordLoc = cast_or_null<dataflow::RecordStorageLocation>(
629634
State.Env.getStorageLocation(*OCE->getArg(0)));
630-
handleConstMemberCall(OCE, RecordLoc, Result, State);
635+
if (!handleConstMemberCall(OCE, RecordLoc, Result, State)) {
636+
// Perform default handling if the call returns an optional,
637+
// but wasn't handled.
638+
if (isSupportedOptionalType(OCE->getType()))
639+
transferCallReturningOptional(OCE, Result, State);
640+
}
631641
}
632642

633643
void handleNonConstMemberCall(const CallExpr *CE,

clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,30 @@ TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) {
37713771
/*IgnoreSmartPointerDereference=*/false);
37723772
}
37733773

3774+
TEST_P(UncheckedOptionalAccessTest, ConstPointerRefAccessor) {
3775+
ExpectDiagnosticsFor(R"cc(
3776+
#include "unchecked_optional_access_test.h"
3777+
3778+
struct A {
3779+
$ns::$optional<int> x;
3780+
};
3781+
3782+
struct PtrWrapper {
3783+
A*& getPtrRef() const;
3784+
void reset(A*);
3785+
};
3786+
3787+
void target(PtrWrapper p) {
3788+
if (p.getPtrRef()->x) {
3789+
*p.getPtrRef()->x;
3790+
p.reset(nullptr);
3791+
*p.getPtrRef()->x; // [[unsafe]]
3792+
}
3793+
}
3794+
)cc",
3795+
/*IgnoreSmartPointerDereference=*/false);
3796+
}
3797+
37743798
TEST_P(UncheckedOptionalAccessTest, SmartPointerAccessorMixed) {
37753799
ExpectDiagnosticsFor(R"cc(
37763800
#include "unchecked_optional_access_test.h"

0 commit comments

Comments
 (0)