-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][dataflow] Fix unsupported types always being equal #129502
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
Conversation
Previously when the framework encountered unsupported values, they were always treated as equal when comparing with `==`, regardless of their actual values being different. Now the two sides are only equal if there's a Value assigned to them. Added a Value assignment for `nullptr`, to handle the special case of `nullptr == nullptr`.
@llvm/pr-subscribers-clang-analysis @llvm/pr-subscribers-clang Author: Discookie (Discookie) ChangesPreviously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with Added a Value assignment for Full diff: https://github.com/llvm/llvm-project/pull/129502.diff 2 Files Affected:
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 9c54eb16d2224..e17a16a3b75d0 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -60,7 +60,9 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
Value *LHSValue = Env.getValue(LHS);
Value *RHSValue = Env.getValue(RHS);
- if (LHSValue == RHSValue)
+ // When two unsupported values are compared, both are nullptr. Only supported
+ // values should evaluate to equal.
+ if (LHSValue == RHSValue && LHSValue)
return Env.getBoolLiteralValue(true);
if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
@@ -798,6 +800,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));
}
+ // Untyped nullptr's aren't handled by NullToPointer casts, so they need to be
+ // handled separately.
+ void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
+ auto &NullPointerVal =
+ Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
+ Env.setValue(*S, NullPointerVal);
+ }
+
void VisitParenExpr(const ParenExpr *S) {
// The CFG does not contain `ParenExpr` as top-level statements in basic
// blocks, however manual traversal to sub-expressions may encounter them.
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 0f731f4532535..f52b73dbbdc57 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -4974,6 +4974,41 @@ TEST(TransferTest, IntegerLiteralEquality) {
});
}
+TEST(TransferTest, UnsupportedValueEquality) {
+ std::string Code = R"(
+ // An explicitly unsupported type by the framework.
+ enum class EC {
+ A,
+ B
+ };
+
+ void target() {
+ EC ec = EC::A;
+
+ bool unsupported_eq_same = (EC::A == EC::A);
+ bool unsupported_eq_other = (EC::A == EC::B);
+ bool unsupported_eq_var = (ec == EC::B);
+
+ (void)0; // [[p]]
+ }
+ )";
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ // We do not model the values of unsupported types, so this
+ // seemingly-trivial case will not be true either.
+ EXPECT_TRUE(isa<AtomicBoolValue>(
+ getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_same")));
+ EXPECT_TRUE(isa<AtomicBoolValue>(
+ getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_other")));
+ EXPECT_TRUE(isa<AtomicBoolValue>(
+ getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_var")));
+ });
+}
+
TEST(TransferTest, CorrelatedBranches) {
std::string Code = R"(
void target(bool B, bool C) {
|
Hi, sorry, I should have run more tests first, but we just noticed a crash in a user of the dataflow framework (around this test https://github.com/google/crubit/blob/859520eca82d60a169fb85cdbf648c57d0a14a99/nullability/test/smart_pointers_diagnosis.cc#L57 ) I'd like to revert for now to investigate. It may have something to do with the added |
…129761) Reverts #129502 seeing new crashes around https://github.com/google/crubit/blob/859520eca82d60a169fb85cdbf648c57d0a14a99/nullability/test/smart_pointers_diagnosis.cc#L57 Would like some time to investigate.
…ng equal" (#129761) Reverts llvm/llvm-project#129502 seeing new crashes around https://github.com/google/crubit/blob/859520eca82d60a169fb85cdbf648c57d0a14a99/nullability/test/smart_pointers_diagnosis.cc#L57 Would like some time to investigate.
Ah I see, thanks for letting me know! I'll test a bit more as well, and add more tests as well if I find something. One of the things I could see an issue with, is that technically the nullptr literal doesn't have a pointee type, since it's a nullptr_t. |
Sorry for the delay! I ran a few more tests and the downstream null analysis over a corpus of code with a small change to the patch. The small tweak (below) seems to pass the tests and your fix helps cover more code, as expected =) I think the issue is that the downstream code doesn't expect to It would take more to change that assumption thoroughly. So a suggestion is to:
WDYT ? |
Sounds good to me, thanks for investigating! Opened #131575 with the recommended change. In the future, it would be nice indeed for nullptr literals to have some kind of Value - I also encountered this as a pain point in my own experimental checker. But with the presence of smart pointers, it indeed needs more thought than this simple fix. |
Drive-by comment.
I think this is the correct way to model things, and it shouldn't be changed. Note that if you compare a pointer to
This is one way of doing this, and I don't really see any issues with this. If we gave I don't think it's worth creating a new |
Thanks, Martin, for the checking over the |
Previously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with `==`, regardless of their actual values being different. Now the two sides are only equal if there's a Value assigned to them. Added a Value assignment for `nullptr`, to handle the special case of `nullptr == nullptr`.
…lvm#129761) Reverts llvm#129502 seeing new crashes around https://github.com/google/crubit/blob/859520eca82d60a169fb85cdbf648c57d0a14a99/nullability/test/smart_pointers_diagnosis.cc#L57 Would like some time to investigate.
…31575) Relands #129502. Previously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with `==`, regardless of their actual values being different. Now the two sides are only equal if there's a Value assigned to them. Added handling for the special case of `nullptr == nullptr`, to preserve the behavior of untyped `nullptr` having no value.
Previously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with
==
, regardless of their actual values being different.Now the two sides are only equal if there's a Value assigned to them.
Added a Value assignment for
nullptr
, to handle the special case ofnullptr == nullptr
.