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 all 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
14 changes: 13 additions & 1 deletion .ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ if [[ "${GROUP}" == downstream* && "${SLUGOWNER}" == "opprop" ]]; then
clone_downstream $SECURITY_GIT $SECURITY_BRANCH
test_downstream $SECURITY_GIT $SECURITY_COMMAND
fi

# Universe test
if [[ "${GROUP}" == "downstream-universe" ]]; then
UNIVERSE_GIT=universe
Expand All @@ -102,6 +102,18 @@ if [[ "${GROUP}" == downstream* && "${SLUGOWNER}" == "opprop" ]]; then
clone_downstream $UNIVERSE_GIT $UNIVERSE_BRANCH
test_downstream $UNIVERSE_GIT $UNIVERSE_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
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, downstream-universe ]
group: [ cfi-tests, downstream-ontology, downstream-security-demo, downstream-universe, downstream-value-inference ]
jdk: [ 8, 11 ]
runs-on: ubuntu-latest
steps:
Expand Down
9 changes: 3 additions & 6 deletions src/checkers/inference/DefaultSlotManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -581,10 +581,7 @@ public ExistentialVariableSlot createExistentialVariableSlot(Slot potentialSlot,
* @param rhsAtm atm of right operand
* @return type kind of the arithmetic operation
*/
private TypeKind getArithmeticResultKind(AnnotatedTypeMirror lhsAtm, AnnotatedTypeMirror rhsAtm) {
TypeMirror lhsType = lhsAtm.getUnderlyingType();
TypeMirror rhsType = rhsAtm.getUnderlyingType();

private TypeKind getArithmeticResultKind(TypeMirror lhsType, TypeMirror rhsType) {
assert (TypesUtils.isPrimitiveOrBoxed(lhsType) && TypesUtils.isPrimitiveOrBoxed(rhsType));

if (TypesUtils.isFloatingPoint(lhsType) || TypesUtils.isFloatingPoint(rhsType)) {
Expand All @@ -601,7 +598,7 @@ private TypeKind getArithmeticResultKind(AnnotatedTypeMirror lhsAtm, AnnotatedTy

@Override
public ArithmeticVariableSlot createArithmeticVariableSlot(
AnnotationLocation location, AnnotatedTypeMirror lhsAtm, AnnotatedTypeMirror rhsAtm) {
AnnotationLocation location, TypeMirror lhs, TypeMirror rhs) {
if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) {
throw new BugInCF(
"Cannot create an ArithmeticVariableSlot with a missing annotation location.");
Expand All @@ -612,7 +609,7 @@ public ArithmeticVariableSlot createArithmeticVariableSlot(
}

// create the arithmetic var slot if it doesn't exist for the given location
TypeKind kind = getArithmeticResultKind(lhsAtm, rhsAtm);
TypeKind kind = getArithmeticResultKind(lhs, rhs);
ArithmeticVariableSlot slot = new ArithmeticVariableSlot(nextId(), location, kind);
addToSlots(slot);
arithmeticSlotCache.put(location, slot.getId());
Expand Down
2 changes: 1 addition & 1 deletion src/checkers/inference/SlotManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public interface SlotManager {
* @return the ArithmeticVariableSlot for the given location
*/
ArithmeticVariableSlot createArithmeticVariableSlot(
AnnotationLocation location, AnnotatedTypeMirror lhsAtm, AnnotatedTypeMirror rhsAtm);
AnnotationLocation location, TypeMirror lhsType, TypeMirror rhsType);

/**
* Create new ComparisonVariableSlot at the given location and return a reference to it if no
Expand Down
98 changes: 98 additions & 0 deletions src/checkers/inference/dataflow/InferenceTransfer.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package checkers.inference.dataflow;

import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
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.dataflow.expression.JavaExpression;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
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.Tree;
Expand All @@ -31,6 +36,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 @@ -401,4 +408,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.
JavaExpression rec;
rec = JavaExpression.fromNode(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);
}
}
14 changes: 12 additions & 2 deletions src/checkers/inference/dataflow/InferenceValue.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package checkers.inference.dataflow;

import checkers.inference.model.ComparisonVariableSlot;
import checkers.inference.util.InferenceUtil;
import javax.lang.model.type.TypeVariable;
import org.checkerframework.framework.flow.CFValue;
Expand Down Expand Up @@ -153,9 +154,18 @@ public CFValue mostSpecificFromSlot(final Slot thisSlot, final Slot otherSlot, f
return other;
}

if (thisSlot instanceof ComparisonVariableSlot
&& ((ComparisonVariableSlot) thisSlot).getRefined().equals(otherSlot)) {
return this;
}
if (otherSlot instanceof ComparisonVariableSlot
&& ((ComparisonVariableSlot) otherSlot).getRefined().equals(thisSlot)) {
return other;
}

if (thisSlot instanceof VariableSlot) {
// Check if one of these has refinement variables that were merged to the other.
for (RefinementVariableSlot slot : ((VariableSlot) thisSlot).getRefinedToSlots()) {
for (VariableSlot slot : ((VariableSlot) thisSlot).getRefinedToSlots()) {
if (slot.isMergedTo(otherSlot)) {
return other;
}
Expand All @@ -164,7 +174,7 @@ public CFValue mostSpecificFromSlot(final Slot thisSlot, final Slot otherSlot, f

if (otherSlot instanceof VariableSlot) {
// Same as above
for (RefinementVariableSlot slot : ((VariableSlot) otherSlot).getRefinedToSlots()) {
for (VariableSlot slot : ((VariableSlot) otherSlot).getRefinedToSlots()) {
if (slot.isMergedTo(thisSlot)) {
return this;
}
Expand Down
10 changes: 10 additions & 0 deletions src/checkers/inference/model/ArithmeticConstraint.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ public static ArithmeticOperationKind fromTreeKind(Kind kind) {
return OR;
case XOR:
return XOR;
case PLUS_ASSIGNMENT:
return PLUS;
case MINUS_ASSIGNMENT:
return MINUS;
case MULTIPLY_ASSIGNMENT:
return MULTIPLY;
case DIVIDE_ASSIGNMENT:
return DIVIDE;
case REMAINDER_ASSIGNMENT:
return REMAINDER;
default:
throw new BugInCF("There are no defined ArithmeticOperationKinds "
+ "for the given com.sun.source.tree.Tree.Kind: " + kind);
Expand Down
4 changes: 2 additions & 2 deletions src/checkers/inference/model/VariableSlot.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public abstract class VariableSlot extends Slot {
private AnnotationLocation location;

/** Refinement variables that refine this slot. */
private final Set<RefinementVariableSlot> refinedToSlots = new HashSet<>();
private final Set<VariableSlot> refinedToSlots = new HashSet<>();

/**
* Create a Slot with the given annotation location.
Expand All @@ -53,7 +53,7 @@ public void setLocation(AnnotationLocation location) {
this.location = location;
}

public Set<RefinementVariableSlot> getRefinedToSlots() {
public Set<VariableSlot> getRefinedToSlots() {
return refinedToSlots;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package checkers.inference.solver.backend.z3smt.encoder;

import java.util.Collection;
import java.util.logging.Logger;

import checkers.inference.InferenceMain;
import com.microsoft.z3.Context;
import com.microsoft.z3.Expr;

import checkers.inference.model.ArithmeticConstraint;
import checkers.inference.model.CombineConstraint;
import checkers.inference.model.ComparableConstraint;
import checkers.inference.model.Constraint;
import checkers.inference.model.EqualityConstraint;
import checkers.inference.model.ExistentialConstraint;
import checkers.inference.model.ImplicationConstraint;
import checkers.inference.model.InequalityConstraint;
import checkers.inference.model.PreferenceConstraint;
import checkers.inference.model.SubtypeConstraint;
import checkers.inference.solver.backend.z3smt.Z3SmtFormatTranslator;
import checkers.inference.solver.frontend.Lattice;
Expand All @@ -22,6 +18,8 @@
public abstract class Z3SmtSoftConstraintEncoder<SlotEncodingT, SlotSolutionT>
extends Z3SmtAbstractConstraintEncoder<SlotEncodingT, SlotSolutionT> {

private static final Logger logger = Logger.getLogger(Z3SmtSoftConstraintEncoder.class.getName());

protected final StringBuilder softConstraints;

public Z3SmtSoftConstraintEncoder(
Expand Down Expand Up @@ -60,7 +58,11 @@ public String encodeAndGetSoftConstraints(Collection<Constraint> constraints) {
encodeSoftInequalityConstraint((InequalityConstraint) constraint);

} else {
throw new BugInCF("Soft constraint for " + constraint.getClass().getName() + " is not supported");
if (InferenceMain.isHackMode()) {
logger.warning("Soft constraint for " + constraint.getClass().getName() + " is not supported");
} else {
throw new BugInCF("Soft constraint for " + constraint.getClass().getName() + " is not supported");
}
}
}
String res = softConstraints.toString();
Expand Down
19 changes: 19 additions & 0 deletions testdata/ostrusted-inferrable-test/Comparison.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import ostrusted.qual.OsTrusted;
import ostrusted.qual.OsUntrusted;

public class Comparison {

void foo(@OsUntrusted Object o) {
if (o == null) {
bar(o);
}
}

@OsTrusted
Object bar(Object o) {
// :: fixable-error: (return.type.incompatible)
return o;
}

}