Skip to content

Clarify error messages in FieldRefValidator #1653

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

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
128 changes: 97 additions & 31 deletions src/main/java/soot/jimple/validation/FieldRefValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,16 @@
import soot.Body;
import soot.ResolutionFailedException;
import soot.SootField;
import soot.SootFieldRef;
import soot.SootMethod;
import soot.Unit;
import soot.baf.BafBody;
import soot.baf.FieldArgInst;
import soot.baf.FieldGetInst;
import soot.baf.FieldPutInst;
import soot.baf.Inst;
import soot.baf.StaticGetInst;
import soot.baf.StaticPutInst;
import soot.jimple.FieldRef;
import soot.jimple.InstanceFieldRef;
import soot.jimple.StaticFieldRef;
Expand All @@ -37,6 +45,10 @@
import soot.validation.UnitValidationException;
import soot.validation.ValidationException;

/**
* @author Alexandre Bartel
* @author Timothy Hoffman
*/
public enum FieldRefValidator implements BodyValidator {
INSTANCE;

Expand All @@ -49,46 +61,100 @@ public static FieldRefValidator v() {
*/
@Override
public void validate(Body body, List<ValidationException> exceptions) {
SootMethod method = body.getMethod();
final SootMethod method = body.getMethod();
if (method.isAbstract()) {
return;
}

final ValidatorImpl<?> vi;
if (body instanceof BafBody) {
vi = new ValidatorImpl<Inst>(body, exceptions) {
@Override
public void check(Unit unit) {
Inst inst = (Inst) unit;
if (inst.containsFieldRef()) {
assert (inst instanceof FieldArgInst); // interface that defines getFieldRef()
check(unit, ((FieldArgInst) unit).getFieldRef(), inst);
}
}

@Override
protected boolean isValidStaticRef(Inst refToCheck) {
return (refToCheck instanceof StaticPutInst) || (refToCheck instanceof StaticGetInst);
}

@Override
protected boolean isValidNonStaticRef(Inst refToCheck) {
return (refToCheck instanceof FieldPutInst) || (refToCheck instanceof FieldGetInst);
}
};
} else {
vi = new ValidatorImpl<FieldRef>(body, exceptions) {
@Override
public void check(Unit unit) {
Stmt stmt = (Stmt) unit;
if (stmt.containsFieldRef()) {
FieldRef ref = stmt.getFieldRef();
check(unit, ref.getFieldRef(), ref);
}
}

@Override
protected boolean isValidStaticRef(FieldRef refToCheck) {
return (refToCheck instanceof StaticFieldRef);
}

@Override
protected boolean isValidNonStaticRef(FieldRef refToCheck) {
return (refToCheck instanceof InstanceFieldRef);
}
};
}

// Run the validator on all units in the body
for (Unit unit : body.getUnits().getNonPatchingChain()) {
Stmt s = (Stmt) unit;
if (!s.containsFieldRef()) {
continue;
vi.check(unit);
}
}

private static abstract class ValidatorImpl<T> {

private final Body body;
private final List<ValidationException> exs;

public ValidatorImpl(Body body, List<ValidationException> exceptions) {
this.body = body;
this.exs = exceptions;
}

public abstract void check(Unit unit);

protected abstract boolean isValidStaticRef(T refToCheck);

protected abstract boolean isValidNonStaticRef(T refToCheck);

protected final void check(Unit unit, SootFieldRef sRef, T refToCheck) {
SootField field;
try {
field = sRef.resolve();
} catch (ResolutionFailedException e) {
exs.add(new UnitValidationException(unit, body, "Unable to resolve SootFieldRef " + sRef + ": " + e.getMessage()));
field = null;
}
FieldRef fr = s.getFieldRef();

if (fr instanceof StaticFieldRef) {
StaticFieldRef v = (StaticFieldRef) fr;
try {
SootField field = v.getField();
if (field == null) {
exceptions.add(new UnitValidationException(unit, body, "Resolved field is null: " + fr.toString()));
} else if (!field.isStatic() && !field.isPhantom()) {
exceptions
.add(new UnitValidationException(unit, body, "Trying to get a static field which is non-static: " + v));
if (field == null) {
exs.add(new UnitValidationException(unit, body, "SootFieldRef resolved to null: " + sRef));
} else if (!field.isPhantom()) {
if (field.isStatic()) {
if (!isValidStaticRef(refToCheck)) {
String s = refToCheck.getClass().getName();
exs.add(new UnitValidationException(unit, body, "Used " + s + " for static field " + sRef));
}
} catch (ResolutionFailedException e) {
exceptions.add(new UnitValidationException(unit, body, "Trying to get a static field which is non-static: " + v));
}
} else if (fr instanceof InstanceFieldRef) {
InstanceFieldRef v = (InstanceFieldRef) fr;

try {
SootField field = v.getField();
if (field == null) {
exceptions.add(new UnitValidationException(unit, body, "Resolved field is null: " + fr.toString()));
} else if (field.isStatic() && !field.isPhantom()) {
exceptions.add(new UnitValidationException(unit, body, "Trying to get an instance field which is static: " + v));
} else {
if (!isValidNonStaticRef(refToCheck)) {
String s = refToCheck.getClass().getName();
exs.add(new UnitValidationException(unit, body, "Used " + s + " for non-static field " + sRef));
}
} catch (ResolutionFailedException e) {
exceptions.add(new UnitValidationException(unit, body, "Trying to get an instance field which is static: " + v));
}
} else {
throw new AssertionError("unknown field ref: " + fr);
}
}
}
Expand Down
Loading