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

Add downstreams of value-inference #331

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
528c2d5
Added operation kind for comparable constraints encoder and its slot
txiang61 Oct 23, 2019
32777f4
removed comparable slot
txiang61 Nov 1, 2019
6c475a9
remove unused code comparable slot cache
txiang61 Nov 7, 2019
80b09d7
Merge remote-tracking branch 'opprop/master' into binary_op
txiang61 Nov 15, 2019
3f4a4a0
added comparable operation kind ANY and clean up code
txiang61 Nov 15, 2019
97e7261
Change comparable constraint structure and rename operators
txiang61 Nov 21, 2019
db4f8b5
Merge remote-tracking branch 'opprop/master' into binary_op
txiang61 May 20, 2020
e2481ef
Merge remote-tracking branch 'opprop/master' into binary_op
txiang61 Jun 26, 2020
9055975
Add comparison constraint instead of modifying comparable constriant …
txiang61 Jun 26, 2020
b6e269c
clean up
txiang61 Jun 26, 2020
5b7df57
Update ComparisonVariableSlot.java
txiang61 Jun 26, 2020
7cc9647
Update ComparisonConstraint.java
txiang61 Jun 26, 2020
18eb89b
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang May 28, 2021
d7f746f
fix compile error
d367wang Jun 3, 2021
110eef2
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Jun 3, 2021
73c4ac9
separate comparable and comparison
d367wang Jun 4, 2021
300e147
bug-fix
d367wang Jun 4, 2021
45c9872
refine comparison operand with comparison variable slots
d367wang Jun 5, 2021
2e4ccc0
add test case
d367wang Jun 5, 2021
73690ea
add downstream value inference
d367wang May 30, 2021
bb1653c
add units inference as downstreamOC
d367wang Jun 5, 2021
cfd51e9
some refactors about z3smt constraint encoder
d367wang Jun 6, 2021
ae7633b
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Jun 7, 2021
4bf1456
fix bugs to pass value-inference
d367wang Jun 10, 2021
10353f1
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Aug 9, 2021
1eda4d7
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Sep 1, 2021
26e89df
fix compile-error
d367wang Sep 1, 2021
006849d
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Dec 17, 2021
447ba2e
config CI projects
d367wang Dec 17, 2021
883eabc
encode ComparisonVariableSlot
d367wang Dec 17, 2021
1b3f8a9
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Jan 13, 2022
19a7ade
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Jan 26, 2022
699c4f8
add arithmetic kind for compound assignment
d367wang Feb 6, 2022
898e2c2
workaround for unsupported kinds of soft constraints
d367wang Feb 6, 2022
f224e14
undo changes
d367wang Feb 6, 2022
fce992b
Merge branch 'master' of https://github.com/opprop/checker-framework-…
d367wang Feb 19, 2022
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
24 changes: 24 additions & 0 deletions .ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,30 @@ if [[ "${GROUP}" == downstream* && "${SLUGOWNER}" == "opprop" ]]; then
clone_downstream $SECURITY_GIT $SECURITY_BRANCH
test_downstream $SECURITY_GIT $SECURITY_COMMAND
fi

# Value inference test
if [[ "${GROUP}" == "downstream-value-inference" ]]; then
VALUE_GIT=value-inference
VALUE_BRANCH=master
VALUE_COMMAND="./gradlew build"

./gradlew testLibJar

clone_downstream $VALUE_GIT $VALUE_BRANCH
test_downstream $VALUE_GIT $VALUE_COMMAND
fi

# Unit inference test
if [[ "${GROUP}" == "downstream-units-inference" ]]; then
UNIT_GIT=units-inference
UNIT_BRANCH=master
UNIT_COMMAND="./gradlew build"

./gradlew testLibJar

clone_downstream $UNIT_GIT $UNIT_BRANCH
test_downstream $UNIT_GIT $UNIT_COMMAND
fi
fi

echo Exiting "$(cd "$(dirname "$0")" && pwd -P)/$(basename "$0")" in `pwd`
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
group: [ cfi-tests, downstream-ontology, downstream-security-demo ]
group: [ cfi-tests, downstream-value-inference, downstream-units-inference ]
jdk: [ 8, 11 ]
runs-on: ubuntu-latest
steps:
Expand Down
67 changes: 67 additions & 0 deletions src/checkers/inference/DefaultSlotManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import checkers.inference.model.AnnotationLocation;
import checkers.inference.model.ArithmeticVariableSlot;
import checkers.inference.model.CombVariableSlot;
import checkers.inference.model.ComparisonVariableSlot;
import checkers.inference.model.ConstantSlot;
import checkers.inference.model.ExistentialVariableSlot;
import checkers.inference.model.RefinementVariableSlot;
Expand Down Expand Up @@ -97,6 +98,22 @@ public class DefaultSlotManager implements SlotManager {
*/
private final Map<AnnotationLocation, Integer> arithmeticSlotCache;

/**
* A map of {@link AnnotationLocation} to {@link Integer} for caching
* {@link ComparisonVariableSlot}s. The annotation location uniquely identifies an
* {@link ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding
* {@link ComparisonVariableSlot}.
*/
private final Map<AnnotationLocation, Integer> comparisonThenSlotCache;

/**
* A map of {@link AnnotationLocation} to {@link Integer} for caching
* {@link ComparisonVariableSlot}s. The annotation location uniquely identifies an
* {@link ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding
* {@link ComparisonVariableSlot}.
*/
private final Map<AnnotationLocation, Integer> comparisonElseSlotCache;

private final Set<Class<? extends Annotation>> realQualifiers;
private final ProcessingEnvironment processingEnvironment;

Expand All @@ -119,6 +136,8 @@ public DefaultSlotManager( final ProcessingEnvironment processingEnvironment,
combSlotPairCache = new LinkedHashMap<>();
lubSlotPairCache = new LinkedHashMap<>();
arithmeticSlotCache = new LinkedHashMap<>();
comparisonThenSlotCache = new LinkedHashMap<>();
comparisonElseSlotCache = new LinkedHashMap<>();

if (storeConstants) {
for (Class<? extends Annotation> annoClass : this.realQualifiers) {
Expand Down Expand Up @@ -436,6 +455,54 @@ public ArithmeticVariableSlot getArithmeticVariableSlot(AnnotationLocation locat
}
}

@Override
public ComparisonVariableSlot createComparisonVariableSlot(AnnotationLocation location, Slot refined, boolean thenBranch) {
if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) {
throw new BugInCF(
"Cannot create an ComparisonVariableSlot with a missing annotation location.");
}

// create the comparison var slot if it doesn't exist for the given location
if (thenBranch && !comparisonThenSlotCache.containsKey(location)) {
ComparisonVariableSlot slot = new ComparisonVariableSlot(nextId(), location, refined);
addToSlots(slot);
comparisonThenSlotCache.put(location, slot.getId());
return slot;
}

// create the comparison var slot if it doesn't exist for the given location
if (!thenBranch && !comparisonElseSlotCache.containsKey(location)) {
ComparisonVariableSlot slot = new ComparisonVariableSlot(nextId(), location, refined);
addToSlots(slot);
comparisonElseSlotCache.put(location, slot.getId());
return slot;
}

return getComparisonVariableSlot(location, thenBranch);
}

@Override
public ComparisonVariableSlot getComparisonVariableSlot(AnnotationLocation location, boolean thenBranch) {
if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) {
throw new BugInCF(
"ComparisonVariableSlot are never created with a missing annotation location.");
}
if (thenBranch) {
if (!comparisonThenSlotCache.containsKey(location)) {
return null;
} else {
return (ComparisonVariableSlot) getSlot(comparisonThenSlotCache.get(location));
}
} else {
if (!comparisonElseSlotCache.containsKey(location)) {
return null;
} else {
return (ComparisonVariableSlot) getSlot(comparisonElseSlotCache.get(location));
}
}
}


@Override
public AnnotationMirror createEquivalentVarAnno(AnnotationMirror realQualifier) {
ConstantSlot varSlot = createConstantSlot(realQualifier);
Expand Down
26 changes: 26 additions & 0 deletions src/checkers/inference/SlotManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import checkers.inference.model.AnnotationLocation;
import checkers.inference.model.ArithmeticVariableSlot;
import checkers.inference.model.CombVariableSlot;
import checkers.inference.model.ComparisonVariableSlot;
import checkers.inference.model.ConstantSlot;
import checkers.inference.model.ExistentialVariableSlot;
import checkers.inference.model.RefinementVariableSlot;
Expand Down Expand Up @@ -151,6 +152,31 @@ public interface SlotManager {
*/
ArithmeticVariableSlot getArithmeticVariableSlot(AnnotationLocation location);

/**
* Create new ComparisonVariableSlot at the given location and return a reference to it if no
* ComparisonVariableSlot exists for the location. Otherwise, returns the existing
* ComparisonVariableSlot.
*
* @param location an AnnotationLocation used to locate this variable in code
* @param thenBranch true if is for the then store, false if is for the else store
* @return the ComparisonVariableSlot for the given location
*/
ComparisonVariableSlot createComparisonVariableSlot(AnnotationLocation location, Slot refined, boolean thenBranch);

/**
* Retrieves the ComparisonVariableSlot created for the given location if it has been previously
* created, otherwise null is returned.
*
* This method allows faster retrieval of already created ComparisonVariableSlot during
* traversals of binary comparison trees in an InferenceTransfer subclass, which does not have direct access
* to the ATM containing this slot.
*
* @param location an AnnotationLocation used to locate this variable in code
* @param thenBranch true if is for the then store, false if is for the else store
* @return the ComparisonVariableSlot for the given location, or null if none exists
*/
ComparisonVariableSlot getComparisonVariableSlot(AnnotationLocation location, boolean thenBranch);

/**
* Create a VarAnnot equivalent to the given realQualifier.
*
Expand Down
113 changes: 105 additions & 8 deletions src/checkers/inference/dataflow/InferenceTransfer.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package checkers.inference.dataflow;

import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
import org.checkerframework.dataflow.analysis.FlowExpressions;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.EqualToNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.NotEqualNode;
import org.checkerframework.dataflow.cfg.node.StringConcatenateAssignmentNode;
import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode;
import org.checkerframework.framework.flow.CFStore;
Expand All @@ -21,6 +25,7 @@
import java.util.Map;
import java.util.logging.Logger;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;

import com.sun.source.tree.CompoundAssignmentTree;
Expand All @@ -33,6 +38,8 @@
import checkers.inference.SlotManager;
import checkers.inference.VariableAnnotator;
import checkers.inference.model.AnnotationLocation;
import checkers.inference.model.ComparisonVariableSlot;
import checkers.inference.model.ConstraintManager;
import checkers.inference.model.ExistentialVariableSlot;
import checkers.inference.model.RefinementVariableSlot;
import checkers.inference.model.Slot;
Expand Down Expand Up @@ -63,8 +70,11 @@ public class InferenceTransfer extends CFTransfer {
// case where the correct, inferred RHS has no primary annotation
private Map<Tree, Pair<RefinementVariableSlot, RefinementVariableSlot>> createdTypeVarRefinementVariables = new HashMap<>();

private final InferenceAnnotatedTypeFactory typeFactory;

public InferenceTransfer(InferenceAnalysis analysis) {
super(analysis);
typeFactory = (InferenceAnnotatedTypeFactory) analysis.getTypeFactory();
}

private InferenceAnalysis getInferenceAnalysis() {
Expand Down Expand Up @@ -92,7 +102,6 @@ public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode assignmen

Node lhs = assignmentNode.getTarget();
CFStore store = transferInput.getRegularStore();
InferenceAnnotatedTypeFactory typeFactory = (InferenceAnnotatedTypeFactory) analysis.getTypeFactory();

// Target tree is null for field access's
Tree targetTree = assignmentNode.getTarget().getTree();
Expand Down Expand Up @@ -137,7 +146,7 @@ public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode assignmen
assert false;
}

return storeDeclaration(lhs, (VariableTree) assignmentNode.getTree(), store, typeFactory);
return storeDeclaration(lhs, (VariableTree) assignmentNode.getTree(), store);

} else if (lhs.getTree().getKind() == Tree.Kind.IDENTIFIER
|| lhs.getTree().getKind() == Tree.Kind.MEMBER_SELECT) {
Expand Down Expand Up @@ -179,7 +188,6 @@ public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode assignmen
public TransferResult<CFValue, CFStore> visitStringConcatenateAssignment(StringConcatenateAssignmentNode assignmentNode, TransferInput<CFValue, CFStore> transferInput) {
// TODO: CompoundAssigment trees are not refined, see Issue 9
CFStore store = transferInput.getRegularStore();
InferenceAnnotatedTypeFactory typeFactory = (InferenceAnnotatedTypeFactory) analysis.getTypeFactory();

Tree targetTree = assignmentNode.getLeftOperand().getTree();

Expand Down Expand Up @@ -225,7 +233,7 @@ private TransferResult<CFValue, CFStore> createRefinementVar(Node lhs,
refVar = createdRefinementVariables.get(assignmentTree);
} else {
AnnotationLocation location = VariableAnnotator.treeToLocation(analysis.getTypeFactory(), assignmentTree);
refVar = getInferenceAnalysis().getSlotManager().createRefinementVariableSlot(location, slotToRefine, refineTo);
refVar = slotManager.createRefinementVariableSlot(location, slotToRefine, refineTo);

// Fields from library methods can be refined, but the slotToRefine is a ConstantSlot
// which does not have a refined slots field.
Expand All @@ -236,7 +244,7 @@ private TransferResult<CFValue, CFStore> createRefinementVar(Node lhs,
createdRefinementVariables.put(assignmentTree, refVar);
}

atm.replaceAnnotation(getInferenceAnalysis().getSlotManager().getAnnotation(refVar));
atm.replaceAnnotation(slotManager.getAnnotation(refVar));

// add refinement variable value to output
CFValue result = analysis.createAbstractValue(atm);
Expand Down Expand Up @@ -379,12 +387,10 @@ private TransferResult<CFValue, CFStore> createTypeVarRefinementVars(Node lhs, T
* @param lhs
* @param assignmentTree
* @param store
* @param typeFactory
* @return
*/
private TransferResult<CFValue, CFStore> storeDeclaration(Node lhs,
VariableTree assignmentTree, CFStore store,
InferenceAnnotatedTypeFactory typeFactory) {
VariableTree assignmentTree, CFStore store) {

AnnotatedTypeMirror atm = typeFactory.getAnnotatedType(assignmentTree);
CFValue result = analysis.createAbstractValue(atm);
Expand All @@ -395,4 +401,95 @@ private TransferResult<CFValue, CFStore> storeDeclaration(Node lhs,
private boolean isDeclarationWithInitializer(AssignmentNode assignmentNode) {
return (assignmentNode.getTree().getKind() == Tree.Kind.VARIABLE);
}


private void createComparisonVariableSlot(Node node, CFStore thenStore, CFStore elseStore) {
// Only create refinement comparison slot for variables
// TODO: deal with comparison between more complex expressions
Node var = node;
if (node instanceof AssignmentNode) {
AssignmentNode a = (AssignmentNode) node;
var = a.getTarget();
}
if (!(var instanceof LocalVariableNode) && !(var instanceof FieldAccessNode)) {
return;
}
Tree tree = var.getTree();
ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager();
SlotManager slotManager = getInferenceAnalysis().getSlotManager();

AnnotatedTypeMirror atm = typeFactory.getAnnotatedType(tree);
Slot slotToRefine = slotManager.getSlot(atm);

// TODO: Understand why there are null slots
if (InferenceMain.isHackMode(slotToRefine == null)) {
logger.fine("HackMode: slotToRefine is null !");
return;
}

if (slotToRefine instanceof RefinementVariableSlot) {
slotToRefine = ((RefinementVariableSlot) slotToRefine).getRefined();
assert !(slotToRefine instanceof RefinementVariableSlot);
}

AnnotationLocation location =
VariableAnnotator.treeToLocation(analysis.getTypeFactory(), tree);
// TODO: find out why there are missing location
if (InferenceMain.isHackMode(location == AnnotationLocation.MISSING_LOCATION)) {
logger.fine("HackMode: create ComparisonVariableSlot on MISSING_LOCATION !");
return;
}
ComparisonVariableSlot thenSlot = slotManager.createComparisonVariableSlot(location, slotToRefine, true);
constraintManager.addSubtypeConstraint(thenSlot, slotToRefine);
ComparisonVariableSlot elseSlot = slotManager.createComparisonVariableSlot(location, slotToRefine, false);
constraintManager.addSubtypeConstraint(elseSlot, slotToRefine);

if (slotToRefine instanceof VariableSlot) {
// ComparisonVariableSlots stores the refined value after comparison, so add it to the "refinedTo" list
((VariableSlot) slotToRefine).getRefinedToSlots().add(thenSlot);
((VariableSlot) slotToRefine).getRefinedToSlots().add(elseSlot);
}

AnnotationMirror thenAm = slotManager.getAnnotation(thenSlot);
AnnotationMirror elseAm = slotManager.getAnnotation(elseSlot);

// If node is assignment, iterate over lhs; otherwise, just node.
FlowExpressions.Receiver rec;
rec = FlowExpressions.internalReprOf(getInferenceAnalysis().getTypeFactory(), var);
thenStore.clearValue(rec);
thenStore.insertValue(rec, thenAm);
elseStore.clearValue(rec);
elseStore.insertValue(rec, elseAm);
}

@Override
public TransferResult<CFValue, CFStore> visitEqualTo(
EqualToNode n, TransferInput<CFValue, CFStore> in) {
TransferResult<CFValue, CFStore> result = super.visitEqualTo(n, in);
CFStore thenStore = result.getThenStore();
CFStore elseStore = result.getElseStore();

createComparisonVariableSlot(n.getLeftOperand(), thenStore, elseStore);
createComparisonVariableSlot(n.getRightOperand(), thenStore, elseStore);

CFValue newResultValue =
getInferenceAnalysis()
.createAbstractValue(typeFactory.getAnnotatedType(n.getTree()));
return new ConditionalTransferResult<>(newResultValue, thenStore, elseStore);
}

@Override
public TransferResult<CFValue, CFStore> visitNotEqual(
NotEqualNode n, TransferInput<CFValue, CFStore> in) {
TransferResult<CFValue, CFStore> result = super.visitNotEqual(n, in);
CFStore thenStore = result.getThenStore();
CFStore elseStore = result.getElseStore();

createComparisonVariableSlot(n.getLeftOperand(), thenStore, elseStore);
createComparisonVariableSlot(n.getRightOperand(), thenStore, elseStore);

CFValue newResultValue =
analysis.createAbstractValue(typeFactory.getAnnotatedType(n.getTree()));
return new ConditionalTransferResult<>(newResultValue, thenStore, elseStore);
}
}
Loading