Skip to content

Conversation

@fmayer
Copy link
Contributor

@fmayer fmayer commented Oct 16, 2025

This allows comparison which these status codes

Created using spr 1.3.7
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:analysis labels Oct 16, 2025
@fmayer fmayer requested review from Xazax-hun and jvoung October 16, 2025 21:48
@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2025

@llvm/pr-subscribers-clang

Author: Florian Mayer (fmayer)

Changes

This allows comparison which these status codes


Full diff: https://github.com/llvm/llvm-project/pull/163872.diff

3 Files Affected:

  • (modified) clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp (+40-4)
  • (modified) clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp (+1-1)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp (+30)
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp index 4ebf3e4251dd6..11dd0e73f7089 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp @@ -129,6 +129,24 @@ static auto isComparisonOperatorCall(llvm::StringRef operator_name) { hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType())))); } +static auto isOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasName("::absl::OkStatus")))); +} + +static auto isNotOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasAnyName( + "::absl::AbortedError", "::absl::AlreadyExistsError", + "::absl::CancelledError", "::absl::DataLossError", + "::absl::DeadlineExceededError", "::absl::FailedPreconditionError", + "::absl::InternalError", "::absl::InvalidArgumentError", + "::absl::NotFoundError", "::absl::OutOfRangeError", + "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError", + "::absl::UnauthenticatedError", "::absl::UnavailableError", + "::absl::UnimplementedError", "::absl::UnknownError")))); +} + static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options) { return CFGMatchSwitchBuilder<const Environment, @@ -411,6 +429,22 @@ static void transferComparisonOperator(const CXXOperatorCallExpr* Expr, State.Env.setValue(*Expr, *LhsAndRhsVal); } +static void transferOkStatusCall(const CallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + auto &OkVal = + initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env); + State.Env.assume(OkVal.formula()); +} + +static void transferNotOkStatusCall(const CallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + auto &OkVal = + initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env); + auto &A = State.Env.arena(); + State.Env.assume(A.makeNot(OkVal.formula())); +} CFGMatchSwitch<LatticeTransferState> buildTransferMatchSwitch(ASTContext &Ctx, @@ -427,18 +461,20 @@ buildTransferMatchSwitch(ASTContext &Ctx, transferStatusUpdateCall) .CaseOfCFGStmt<CXXOperatorCallExpr>( isComparisonOperatorCall("=="), - [](const CXXOperatorCallExpr* Expr, const MatchFinder::MatchResult&, - LatticeTransferState& State) { + [](const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, + LatticeTransferState &State) { transferComparisonOperator(Expr, State, /*IsNegative=*/false); }) .CaseOfCFGStmt<CXXOperatorCallExpr>( isComparisonOperatorCall("!="), - [](const CXXOperatorCallExpr* Expr, const MatchFinder::MatchResult&, - LatticeTransferState& State) { + [](const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, + LatticeTransferState &State) { transferComparisonOperator(Expr, State, /*IsNegative=*/true); }) + .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall) + .CaseOfCFGStmt<CallExpr>(isNotOkStatusCall(), transferNotOkStatusCall) .Build(); } diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp index d3dee58651396..461af73ea6c01 100644 --- a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp @@ -1356,7 +1356,7 @@ bool operator==(const Status &lhs, const Status &rhs); bool operator!=(const Status &lhs, const Status &rhs); Status OkStatus(); -Status InvalidArgumentError(char *); +Status InvalidArgumentError(const char *); #endif // STATUS_H )cc"; diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index 99f04cc8fe7e7..e7fe378a6973d 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -2710,6 +2710,36 @@ TEST_P(UncheckedStatusOrAccessModelTest, EqualityCheck) { } } )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() == absl::OkStatus()) + sor.value(); + else + sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::OkStatus()) + sor.value(); // [[unsafe]] + else + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::InvalidArgumentError("oh no")) + sor.value(); // [[unsafe]] + else + sor.value(); // [[unsafe]] + } + )cc"); ExpectDiagnosticsFor( R"cc( #include "unchecked_statusor_access_test_defs.h" 
@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2025

@llvm/pr-subscribers-clang-analysis

Author: Florian Mayer (fmayer)

Changes

This allows comparison which these status codes


Full diff: https://github.com/llvm/llvm-project/pull/163872.diff

3 Files Affected:

  • (modified) clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp (+40-4)
  • (modified) clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp (+1-1)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp (+30)
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp index 4ebf3e4251dd6..11dd0e73f7089 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp @@ -129,6 +129,24 @@ static auto isComparisonOperatorCall(llvm::StringRef operator_name) { hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType())))); } +static auto isOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasName("::absl::OkStatus")))); +} + +static auto isNotOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasAnyName( + "::absl::AbortedError", "::absl::AlreadyExistsError", + "::absl::CancelledError", "::absl::DataLossError", + "::absl::DeadlineExceededError", "::absl::FailedPreconditionError", + "::absl::InternalError", "::absl::InvalidArgumentError", + "::absl::NotFoundError", "::absl::OutOfRangeError", + "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError", + "::absl::UnauthenticatedError", "::absl::UnavailableError", + "::absl::UnimplementedError", "::absl::UnknownError")))); +} + static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options) { return CFGMatchSwitchBuilder<const Environment, @@ -411,6 +429,22 @@ static void transferComparisonOperator(const CXXOperatorCallExpr* Expr, State.Env.setValue(*Expr, *LhsAndRhsVal); } +static void transferOkStatusCall(const CallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + auto &OkVal = + initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env); + State.Env.assume(OkVal.formula()); +} + +static void transferNotOkStatusCall(const CallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + auto &OkVal = + initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env); + auto &A = State.Env.arena(); + State.Env.assume(A.makeNot(OkVal.formula())); +} CFGMatchSwitch<LatticeTransferState> buildTransferMatchSwitch(ASTContext &Ctx, @@ -427,18 +461,20 @@ buildTransferMatchSwitch(ASTContext &Ctx, transferStatusUpdateCall) .CaseOfCFGStmt<CXXOperatorCallExpr>( isComparisonOperatorCall("=="), - [](const CXXOperatorCallExpr* Expr, const MatchFinder::MatchResult&, - LatticeTransferState& State) { + [](const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, + LatticeTransferState &State) { transferComparisonOperator(Expr, State, /*IsNegative=*/false); }) .CaseOfCFGStmt<CXXOperatorCallExpr>( isComparisonOperatorCall("!="), - [](const CXXOperatorCallExpr* Expr, const MatchFinder::MatchResult&, - LatticeTransferState& State) { + [](const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, + LatticeTransferState &State) { transferComparisonOperator(Expr, State, /*IsNegative=*/true); }) + .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall) + .CaseOfCFGStmt<CallExpr>(isNotOkStatusCall(), transferNotOkStatusCall) .Build(); } diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp index d3dee58651396..461af73ea6c01 100644 --- a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp @@ -1356,7 +1356,7 @@ bool operator==(const Status &lhs, const Status &rhs); bool operator!=(const Status &lhs, const Status &rhs); Status OkStatus(); -Status InvalidArgumentError(char *); +Status InvalidArgumentError(const char *); #endif // STATUS_H )cc"; diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index 99f04cc8fe7e7..e7fe378a6973d 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -2710,6 +2710,36 @@ TEST_P(UncheckedStatusOrAccessModelTest, EqualityCheck) { } } )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() == absl::OkStatus()) + sor.value(); + else + sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::OkStatus()) + sor.value(); // [[unsafe]] + else + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::InvalidArgumentError("oh no")) + sor.value(); // [[unsafe]] + else + sor.value(); // [[unsafe]] + } + )cc"); ExpectDiagnosticsFor( R"cc( #include "unchecked_statusor_access_test_defs.h" 
Created using spr 1.3.7 [skip ci]
Created using spr 1.3.7
Created using spr 1.3.7 [skip ci]
Created using spr 1.3.7
@fmayer
Copy link
Contributor Author

fmayer commented Oct 17, 2025

Created using spr 1.3.7 [skip ci]
Created using spr 1.3.7
Created using spr 1.3.7 [skip ci]
Created using spr 1.3.7
Created using spr 1.3.7 [skip ci]
Created using spr 1.3.7
@fmayer fmayer changed the base branch from users/fmayer/spr/main.flowsensitive-statusor-5n-support-abslokstatus-et-al to main October 22, 2025 19:58
Created using spr 1.3.7
@fmayer fmayer merged commit 764acd8 into main Oct 22, 2025
10 checks passed
@fmayer fmayer deleted the users/fmayer/spr/flowsensitive-statusor-5n-support-abslokstatus-et-al branch October 22, 2025 22:06
mikolaj-pirog pushed a commit to mikolaj-pirog/llvm-project that referenced this pull request Oct 23, 2025
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:analysis clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang Clang issues not falling into any other category

4 participants