-
Notifications
You must be signed in to change notification settings - Fork 356
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
Bug in store propagation #3267
Comments
Thanks for the bug report! Here is a slightly expanded version that shows the expected behavior in a simpler case too (where the Nullness Checker works as expected).
|
Thanks for reporting this bug! It looks like an incorrect CFG is generated when there is an
With a different condition and without a condition, the expected error is produced. Are you running into this issue with something other than |
I did not find it in real code but maybe I can provide some context. I found this issue while developing a plugin with support for typestates. I had something like this: MyIterator it = new MyIterator();
it.hasNext();
if (true) {
it.next();
} And it was not showing an error. My implementation looks at the I was not sure if I did something wrong, or if the issue was with Checker. So I attempted to produce an example with the nullness plugin, and found, what seems to be, a similar issue: the "then" and "else" stores are propagated "each to each", even though what immediately follows the method invocation is not a conditional block, but a regular block with a Overriding protected void propagateStoresTo(...) {
switch (flowRule) {
case EACH_TO_EACH:
if (currentInput.containsTwoStores()
&& succ.getType() == CONDITIONAL_BLOCK // Addition
) { Edit: I suspect that different conditions do not produce an error because |
Found another interesting example: import org.checkerframework.checker.nullness.qual.Nullable;
class Bug {
void foo(@Nullable Object obj) {
if ((obj != null) == false) {
// :: (dereference.of.nullable)
obj.toString(); // BUG: no warning about this dereference
}
}
void bar(@Nullable Object obj) {
if (!(obj == null) == false) {
// :: (dereference.of.nullable)
obj.toString(); // BUG: no warning about this dereference
}
}
void baz(@Nullable Object obj) {
if ((obj == null) == true) {
// :: (dereference.of.nullable)
obj.toString();
}
}
} |
Support decisions with == and complex variations. Fix wrong assumption introduced in 1f9c81 Workaround this issue: typetools/checker-framework#3267
Support decisions with == and complex variations. Fix wrong assumption introduced in 1f9c81 Workaround this issue: typetools/checker-framework/issues/3267
I filed #3274 to fix the original bug report from this issue. The proposed fix removes an optimization, but I doubt it will have a performance impact. I can reproduce your comment about your new typestate checker using the Regex Checker: void bar(String s) {
RegexUtil.isRegex(s);
if (true) {
// :: error: (argument.type.incompatible)
Pattern.compile(s); // Error missing
}
} #3274 doesn't fix that issue. I'll look into wrapping all ExpressionStatements into an assignment to a temporary variable, turning the above code into: void bar(String s) {
boolean res = RegexUtil.isRegex(s);
if (true) {
// :: error: (argument.type.incompatible)
Pattern.compile(s);
}
} which correctly gives an error. I've started #3275 for your latest comment, which seems unrelated to this issue. |
Example
java -jar "checker-framework-3.3.0/checker/dist/checker.jar" -processor org.checkerframework.checker.nullness.NullnessChecker Bug.java
Online demo
Expected result
Current result
Possible explanation
Only recently I started working with Checker, so I am not sure, but I suspect what the issue might be. Since
FlowRule.EACH_TO_EACH
is considered the normal case for store propagation, the "then" and "else" stores resulting from the analysis of the firstobj != null
are propagated "each to each" to thetrue
expression and then to the secondif
statement. I believe that this is incorrect. ProbablyFlowRule.EACH_TO_EACH
should only apply if what immediatly follows is a conditional block? The reason why the second error is caught, I believe, is becauseCFAbstractTransfer#visitVariableDeclaration
returns aRegularTransferResult
, which already combines the two stores, so the propagation works as expected.The text was updated successfully, but these errors were encountered: