Skip to content
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

Introduce bottom store to improve dataflow analysis #167

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7e91f46
initial bottom-store implementation
d367wang Apr 1, 2021
2237641
Merge branch 'master' of https://github.com/opprop/checker-framework …
d367wang May 20, 2021
6ec3d77
Merge branch 'master' of https://github.com/opprop/checker-framework …
d367wang Jul 6, 2021
0122edf
undo import *
d367wang Jul 6, 2021
c276efa
fix compile error
d367wang Aug 4, 2021
cceadf7
fix bug
d367wang Aug 4, 2021
81c8059
add lock bottom store; remove FPs involving if(true/false)
d367wang Aug 5, 2021
887a888
NullnessBottom.getValue returns two qualifiers
d367wang Aug 5, 2021
9af8f2e
xxxBottomStore.getValue returns abstract value with bottom annotations
d367wang Aug 5, 2021
0a4adad
remove @Nullable on xxxBottomStore.getValue
d367wang Aug 5, 2021
6775dfa
fix bug
d367wang Aug 5, 2021
68b238b
make bottom-store logic coherent to CFAbstract classes
d367wang Aug 9, 2021
826d25a
Merge branch 'master' of https://github.com/opprop/checker-framework …
d367wang Aug 27, 2021
d6ddb82
adapt expected files
d367wang Aug 27, 2021
ee35b60
Merge branch 'master' of https://github.com/opprop/checker-framework …
d367wang Sep 16, 2021
080ff48
remove BOTH_TO_THEN and BOTH_TO_ELSE
d367wang Sep 16, 2021
d70186b
fix bug and refactor
d367wang Sep 17, 2021
5b616d3
hack CFAbastractValue.combineOneAnnotation
d367wang Sep 22, 2021
e83dea7
only use bottom store when the boolean literal is a condition on its own
d367wang Sep 22, 2021
ea69c0a
suppress intern error
d367wang Sep 22, 2021
2e03227
adapt expected error
d367wang Sep 22, 2021
7408317
change bottom value for lock type system
d367wang Sep 23, 2021
44c97a7
fix bug in bottom store, to resolve the must-call case
d367wang Sep 23, 2021
a6509e5
adapt bottom value for lock type system
d367wang Sep 23, 2021
9041117
no insertion to bottom store
d367wang Sep 28, 2021
40a27ca
add javadoc
d367wang Sep 28, 2021
a131f41
apply default to void methodreturns
d367wang Sep 28, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,19 @@ public class InitializationStore<V extends CFAbstractValue<V>, S extends Initial
* @param sequentialSemantics should the analysis use sequential Java semantics?
*/
public InitializationStore(CFAbstractAnalysis<V, S, ?> analysis, boolean sequentialSemantics) {
super(analysis, sequentialSemantics);
this(analysis, sequentialSemantics, false);
}

/**
* Creates a new InitializationStore.
*
* @param analysis the analysis class this store belongs to
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @param isBottom is the store a bottom store?
*/
public InitializationStore(
CFAbstractAnalysis<V, S, ?> analysis, boolean sequentialSemantics, boolean isBottom) {
super(analysis, sequentialSemantics, isBottom);
initializedFields = new HashSet<>(4);
invariantFields = new HashMap<>(4);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public LockStore createEmptyStore(boolean sequentialSemantics) {
return new LockStore(this, sequentialSemantics);
}

@Override
public LockStore createBottomStore(boolean sequentialSemantics) {
return new LockStore(this, sequentialSemantics, true);
}

@Override
public LockStore createCopiedStore(LockStore s) {
return new LockStore(this, s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
import org.checkerframework.javacutil.AnnotationUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;

/**
* The Lock Store behaves like CFAbstractStore but requires the ability to insert exact annotations.
Expand All @@ -42,7 +45,18 @@ public class LockStore extends CFAbstractStore<CFValue, LockStore> {
private final LockAnnotatedTypeFactory atypeFactory;

public LockStore(LockAnalysis analysis, boolean sequentialSemantics) {
super(analysis, sequentialSemantics);
this(analysis, sequentialSemantics, false);
}

/**
* Constructor for LockStore.
*
* @param analysis the analysis class this store belongs to
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @param isBottom is the store a bottom store?
*/
public LockStore(LockAnalysis analysis, boolean sequentialSemantics, boolean isBottom) {
super(analysis, sequentialSemantics, isBottom);
this.atypeFactory = (LockAnnotatedTypeFactory) analysis.getTypeFactory();
}

Expand Down Expand Up @@ -163,6 +177,14 @@ public void setInConstructorOrInitializer() {
return super.getValue(expr);
}

@Override
protected CFValue getBottomValue(TypeMirror type) {
AnnotationMirror guardBy = ((LockAnnotatedTypeFactory) analysis.getTypeFactory()).GUARDEDBY;
AnnotationMirror lockHeld = ((LockAnnotatedTypeFactory) analysis.getTypeFactory()).LOCKHELD;

return analysis.createAbstractValue(new HashSet<>(Arrays.asList(lockHeld, guardBy)), type);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new HashSet<>(Arrays.asList(lockHeld, guardBy)
Can we replace it with ImmutableSet.of(...)? Or should we store these bottom annotations instead of creating a new set each time this method is invoked?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually there is a final field bottomAnnos in the these store classes that represents the set of bottom annotations. That field is initialized in the constructor with AnnotatedTypeFactory.getBottomAnnotations().

But LockStore is special. We can't use the real bottom annotations, so here the getBottomValue is overriden.

}

@Override
protected String internalVisualize(CFGVisualizer<CFValue, LockStore, ?> viz) {
return viz.visualizeStoreKeyVal("inConstructorOrInitializer", inConstructorOrInitializer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public KeyForStore createEmptyStore(boolean sequentialSemantics) {
return new KeyForStore(this, sequentialSemantics);
}

@Override
public KeyForStore createBottomStore(boolean sequentialSemantics) {
return new KeyForStore(this, sequentialSemantics);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just return createEmptyStore(sequentialSemantics)?

Copy link
Author

@d367wang d367wang Sep 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return new KeyForStore(this, sequentialSemantics, true);

}

@Override
public KeyForStore createCopiedStore(KeyForStore store) {
return new KeyForStore(store);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,21 @@
public class KeyForStore extends CFAbstractStore<KeyForValue, KeyForStore> {
public KeyForStore(
CFAbstractAnalysis<KeyForValue, KeyForStore, ?> analysis, boolean sequentialSemantics) {
super(analysis, sequentialSemantics);
this(analysis, sequentialSemantics, false);
}

/**
* Constructor for KeyForStore.
*
* @param analysis the analysis class this store belongs to
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @param isBottom is the store a bottom store?
*/
public KeyForStore(
CFAbstractAnalysis<KeyForValue, KeyForStore, ?> analysis,
boolean sequentialSemantics,
boolean isBottom) {
super(analysis, sequentialSemantics, isBottom);
}

protected KeyForStore(CFAbstractStore<KeyForValue, KeyForStore> other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public NullnessStore createEmptyStore(boolean sequentialSemantics) {
return new NullnessStore(this, sequentialSemantics);
}

@Override
public NullnessStore createBottomStore(boolean sequentialSemantics) {
return new NullnessStore(this, sequentialSemantics, true);
}

@Override
public NullnessStore createCopiedStore(NullnessStore s) {
return new NullnessStore(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,23 @@ public class NullnessStore extends InitializationStore<NullnessValue, NullnessSt
public NullnessStore(
CFAbstractAnalysis<NullnessValue, NullnessStore, ?> analysis,
boolean sequentialSemantics) {
super(analysis, sequentialSemantics);
this(analysis, sequentialSemantics, false);
}

/**
* Constructor for NullnessStore.
*
* @param analysis the analysis class this store belongs to
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @param isBottom is the store a bottom store?
*/
public NullnessStore(
CFAbstractAnalysis<NullnessValue, NullnessStore, ?> analysis,
boolean sequentialSemantics,
boolean isBottom) {
super(analysis, sequentialSemantics, isBottom);
isPolyNullNonNull = false;
isPolyNullNull = false;
this.isPolyNullNull = false;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why adding this. on line 49 while line 48 doesn't have this.?

}

/**
Expand Down
1 change: 1 addition & 0 deletions checker/tests/formatter/FlowFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static void main(String... p) {
if (false) {
nullAssign = "%s";
}
// :: error: (format.string.invalid)
f.format(nullAssign, "string");
// :: error: (assignment.type.incompatible)
@Format({ConversionCategory.GENERAL}) String err0 = unqual;
Expand Down
3 changes: 0 additions & 3 deletions checker/tests/index/LubIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public static void MinLen(int @MinLen(10) [] arg, int @MinLen(4) [] arg2) {
} else {
arr = arg2;
}
// :: error: (assignment.type.incompatible)
int @MinLen(10) [] res = arr;
int @MinLen(4) [] res2 = arr;
// :: error: (assignment.type.incompatible)
Expand All @@ -24,10 +23,8 @@ public static void Bottom(int @BottomVal [] arg, int @MinLen(4) [] arg2) {
} else {
arr = arg2;
}
// :: error: (assignment.type.incompatible)
int @MinLen(10) [] res = arr;
int @MinLen(4) [] res2 = arr;
// :: error: (assignment.type.incompatible)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes make sense, but they also alter the meaning of this test. Should we write a new test case for the merging of @BottomVal and @MinLen(4)?

int @BottomVal [] res3 = arr;
}

Expand Down
4 changes: 0 additions & 4 deletions checker/tests/initialization/TryFinallyContinue.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ String testWhile1() {
String ans = "x";
while (true) {
if (true) {
// :: error: (return.type.incompatible)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: we are removing all occurences of // :: error: (return.type.incompatible) in this file, and we need some new test cases to cover issue typetools#548.

return ans;
}
if (true) {
Expand Down Expand Up @@ -41,7 +40,6 @@ String testWhile3(boolean cond) {
OUTER:
while (true) {
if (true) {
// :: error: (return.type.incompatible)
return ans;
}

Expand All @@ -66,7 +64,6 @@ String testFor1() {
String ans = "x";
for (; ; ) {
if (true) {
// :: error: (return.type.incompatible)
return ans;
}
if (true) {
Expand Down Expand Up @@ -101,7 +98,6 @@ String testFor3(boolean cond) {
OUTER:
for (; ; ) {
if (true) {
// :: error: (return.type.incompatible)
return ans;
}

Expand Down
1 change: 0 additions & 1 deletion checker/tests/nullness/Issue293.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ void test4() throws Exception {
s = null;
}
} finally {
// :: error: argument.type.incompatible
write(s);
}
}
Expand Down
13 changes: 1 addition & 12 deletions checker/tests/nullness/Issue3622.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ public boolean equals(@Nullable Object obj9) {
public class ImmutableIntList4 {

@Override
@SuppressWarnings(
"contracts.conditional.postcondition.not.satisfied" // TODO: `if` needs the
// BOTH_TO_THEN treatment that ?: gets.
)
@SuppressWarnings("contracts.conditional.postcondition.not.satisfied")
Copy link
Author

@d367wang d367wang Sep 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment for reason for suppressWarning

add another case return true in if and return false in else

public boolean equals(@Nullable Object obj4) {
boolean b;
if (obj4 instanceof ImmutableIntList4) {
Expand All @@ -91,10 +88,6 @@ public boolean equals(@Nullable Object obj4) {
public class ImmutableIntList5 {

@Override
@SuppressWarnings(
"contracts.conditional.postcondition.not.satisfied" // TODO: Need special treatment
// for true and false boolean literals (cut off dead parts of graph).
)
public boolean equals(@Nullable Object obj5) {
return true ? obj5 instanceof ImmutableIntList5 : obj5 instanceof ImmutableIntList5;
}
Expand All @@ -103,10 +96,6 @@ public boolean equals(@Nullable Object obj5) {
public class ImmutableIntList6 {

@Override
@SuppressWarnings(
"contracts.conditional.postcondition.not.satisfied" // TODO: Need special treatment
// for true and false boolean literals (cut off dead parts of graph).
)
public boolean equals(@Nullable Object obj6) {
return true ? obj6 instanceof ImmutableIntList6 : false;
}
Expand Down
11 changes: 11 additions & 0 deletions checker/tests/nullness/flow/DeadBranch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import org.checkerframework.checker.nullness.qual.Nullable;

class DeadBranch {

Object foo(@Nullable Object myObj, boolean x) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need boolean x?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out! I need to add another case using x as the condition.

if (true) {
myObj = new Object();
}
return myObj;
}
}
1 change: 0 additions & 1 deletion checker/tests/resourceleak/ACSocketTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ void replaceVarWithNull(String address, int port, boolean b, boolean c) {
void ownershipTransfer(String address, int port) {
Socket s1 = null;
try {
// :: error: required.method.not.called
s1 = new Socket(address, port);
} catch (IOException e) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,22 +461,6 @@ protected void propagateStoresTo(
Store.Kind.ELSE,
addToWorklistAgain);
break;
case BOTH_TO_THEN:
addStoreBefore(
succ,
node,
currentInput.getRegularStore(),
Store.Kind.THEN,
addToWorklistAgain);
break;
case BOTH_TO_ELSE:
addStoreBefore(
succ,
node,
currentInput.getRegularStore(),
Store.Kind.ELSE,
addToWorklistAgain);
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ public static enum FlowRule {
THEN_TO_THEN,
/** Else store flows to the else of successor. Then store is ignored. */
ELSE_TO_ELSE,
/** Both stores flow to the then of successor. */
BOTH_TO_THEN,
/** Both stores flow to the else of successor. */
BOTH_TO_ELSE,
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2278,12 +2278,11 @@ public Node visitConditionalExpression(ConditionalExpressionTree tree, Void p) {
addLabelForNextNode(trueStart);
Node trueExpr = scan(tree.getTrueExpression(), p);
trueExpr = conditionalExprPromotion(trueExpr, exprType);
extendWithExtendedNode(new UnconditionalJump(merge, FlowRule.BOTH_TO_THEN));
extendWithExtendedNode(new UnconditionalJump(merge));

addLabelForNextNode(falseStart);
Node falseExpr = scan(tree.getFalseExpression(), p);
falseExpr = conditionalExprPromotion(falseExpr, exprType);
extendWithExtendedNode(new UnconditionalJump(merge, FlowRule.BOTH_TO_ELSE));

addLabelForNextNode(merge);
Node node = new TernaryExpressionNode(tree, condition, trueExpr, falseExpr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public FieldInitialValue(FieldAccess fieldDecl, V declared, @Nullable V initiali
/** Instance of the types utility. */
protected final Types types;

/** The singleton of bottom store in dataflow analysis for a specific type system */
protected S bottomStore;

/**
* Create a CFAbstractAnalysis.
*
Expand Down Expand Up @@ -170,10 +173,32 @@ public T createTransferFunction() {
/**
* Returns an empty store of the appropriate type.
*
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @return an empty store of the appropriate type
*/
public abstract S createEmptyStore(boolean sequentialSemantics);

/**
* Create the unique shared instance of bottom store for the underlying type system.
*
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @return the bottom store instance of the appropriate type
*/
public abstract S createBottomStore(boolean sequentialSemantics);

/**
* Get the singleton of the bottom store corresponding to the type.
Copy link
Author

@d367wang d367wang Sep 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... corresponding to the type system

*
* @param sequentialSemantics should the analysis use sequential Java semantics?
* @return the shared instance of bottom store for the underyling type system
*/
public S getBottomStore(boolean sequentialSemantics) {
if (bottomStore == null) {
bottomStore = createBottomStore(sequentialSemantics);
}
return bottomStore;
}

/**
* Returns an identical copy of the store {@code s}.
*
Expand Down
Loading