diff --git a/sootup.core/src/main/java/sootup/core/validation/FieldRefValidator.java b/sootup.core/src/main/java/sootup/core/validation/FieldRefValidator.java index f7a2c07a04a..fee35aa25d8 100644 --- a/sootup.core/src/main/java/sootup/core/validation/FieldRefValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/FieldRefValidator.java @@ -4,7 +4,7 @@ * #%L * Soot - a J*va Optimization Framework * %% - * Copyright (C) 1997-2020 Raja Vallée-Rai, Christian Brüggemann, Markus Schmidt and others + * Copyright (C) 1997-2020 Raja Vallée-Rai, Christian Brüggemann, Markus Schmidt, Akshita Dubey and others * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -24,7 +24,13 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import sootup.core.jimple.common.ref.JFieldRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.model.SootField; import sootup.core.views.View; public class FieldRefValidator implements BodyValidator { @@ -35,31 +41,47 @@ public List validate(Body body, View view) { List validationException = new ArrayList<>(); - // TODO: check copied code from old soot - /* - * SootMethod methodRef = body.getMethod(); if (methodRef.isAbstract()) { return; } - * - * Chain units = body.getUnits().getNonPatchingChain(); - * - * for (Unit unit : units) { Stmt s = (Stmt) unit; if (!s.containsFieldRef()) { continue; } JFieldRef fr = - * s.getFieldRef(); - * - * if (fr instanceof JStaticFieldRef) { JStaticFieldRef v = (JStaticFieldRef) 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)); } } 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)); } } catch - * (ResolutionFailedException e) { exceptions.add(new UnitValidationException(unit, body, - * "Trying to get an instance field which is static: " + v)); } } else { throw new RuntimeException("unknown field ref"); - * } } - */ + List stmts = body.getStmts(); + for (Stmt stmt : stmts) { + if (!stmt.containsFieldRef()) { + continue; + } + JFieldRef fr = stmt.getFieldRef(); + + if (fr instanceof JStaticFieldRef) { + JStaticFieldRef v = (JStaticFieldRef) fr; + + Optional fieldOpt = view.getField(v.getFieldSignature()); + if (!fieldOpt.isPresent()) { + validationException.add(new ValidationException(v, "Resolved field is empty: ")); + } else { + SootField field = fieldOpt.get(); + if (!field.isStatic()) { + validationException.add( + new ValidationException( + fr, "Trying to get a static field which is non-static: " + v)); + } + } + } else if (fr instanceof JInstanceFieldRef) { + JInstanceFieldRef v = (JInstanceFieldRef) fr; + + Optional fieldOpt = view.getField(v.getFieldSignature()); + if (!fieldOpt.isPresent()) { + validationException.add( + new ValidationException(fr, "Resolved field is null: " + fr.toString())); + } else { + SootField field = fieldOpt.get(); + if (field.isStatic()) { + validationException.add( + new ValidationException( + fr, "Trying to get an instance field which is static: " + v)); + } + } + } else { + throw new RuntimeException("unknown field ref"); + } + } return validationException; } diff --git a/sootup.tests/src/test/java/sootup/tests/validator/FieldRefValidatorTest.java b/sootup.tests/src/test/java/sootup/tests/validator/FieldRefValidatorTest.java new file mode 100644 index 00000000000..289e04003f6 --- /dev/null +++ b/sootup.tests/src/test/java/sootup/tests/validator/FieldRefValidatorTest.java @@ -0,0 +1,117 @@ +package sootup.tests.validator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import categories.Java8Test; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.model.SootClass; +import sootup.core.model.SourceType; +import sootup.core.signatures.PackageName; +import sootup.core.types.ClassType; +import sootup.core.validation.FieldRefValidator; +import sootup.core.validation.ValidationException; +import sootup.jimple.parser.JimpleAnalysisInputLocation; +import sootup.jimple.parser.JimpleView; + +@Category(Java8Test.class) +public class FieldRefValidatorTest { + + FieldRefValidator fieldRefValidator; + JimpleView jimpleView; + Collection> classes; + + @Before + public void Setup() { + + fieldRefValidator = new FieldRefValidator(); + + ClassType classTypeFieldRefValidator = + new ClassType() { + @Override + public boolean isBuiltInClass() { + return false; + } + + @Override + public String getFullyQualifiedName() { + return "jimple.FieldRefValidator"; + } + + @Override + public String getClassName() { + return "FieldRefValidator"; + } + + @Override + public PackageName getPackageName() { + return new PackageName("jimple"); + } + }; + + String classPath = "src/test/resources/validator/jimple"; + JimpleAnalysisInputLocation jimpleInputLocation = + new JimpleAnalysisInputLocation(Paths.get(classPath), SourceType.Application); + + jimpleView = new JimpleView(jimpleInputLocation); + final Optional> classSource1 = jimpleView.getClass(classTypeFieldRefValidator); + assertFalse(classSource1.isPresent()); + + classes = new HashSet<>(); // Set to track the classes to check + + for (SootClass aClass : jimpleView.getClasses()) { + if (!aClass.isLibraryClass()) { + classes.add(aClass); + } + } + } + + @Test + public void testFieldRefValidatorSuccess() { + List validationExceptions_success; + + validationExceptions_success = + fieldRefValidator.validate( + classes.stream() + .filter(c -> c.getType().getClassName().equals("FieldRefValidator")) + .findFirst() + .get() + .getMethods() + .stream() + .filter(m -> m.getName().equals("testFieldRefValidator_pass")) + .map(m -> m.getBody()) + .findFirst() + .get(), + jimpleView); + + assertEquals(0, validationExceptions_success.size()); + } + + @Test + public void testFieldRefValidatorFailure() { + List validationExceptions_fail; + + validationExceptions_fail = + fieldRefValidator.validate( + classes.stream() + .filter(c -> c.getType().getClassName().equals("FieldRefValidator")) + .findFirst() + .get() + .getMethods() + .stream() + .filter(m -> m.getName().equals("testFieldRefValidator_fail")) + .map(m -> m.getBody()) + .findFirst() + .get(), + jimpleView); + + assertEquals(2, validationExceptions_fail.size()); + } +} diff --git a/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java b/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java index ebd12db02f3..d414ac2e789 100644 --- a/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java +++ b/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import categories.Java8Test; import java.nio.file.Paths; import java.util.Collection; import java.util.HashSet; @@ -10,6 +11,7 @@ import java.util.Optional; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.categories.Category; import sootup.core.model.SootClass; import sootup.core.model.SourceType; import sootup.core.signatures.PackageName; @@ -19,6 +21,7 @@ import sootup.jimple.parser.JimpleAnalysisInputLocation; import sootup.jimple.parser.JimpleView; +@Category(Java8Test.class) public class NewValidatorTest { NewValidator validator; diff --git a/sootup.tests/src/test/resources/validator/jimple/FieldRefValidator.jimple b/sootup.tests/src/test/resources/validator/jimple/FieldRefValidator.jimple new file mode 100644 index 00000000000..be5d8c2d15b --- /dev/null +++ b/sootup.tests/src/test/resources/validator/jimple/FieldRefValidator.jimple @@ -0,0 +1,50 @@ +public super class FieldRefValidator extends java.lang.Object +{ + private int x; + + private static int y; + + public void () + { + FieldRefValidator $l0; + + + $l0 := @this: FieldRefValidator; + specialinvoke $l0.()>(); + + return; + } + + static void () + { + + = 5; + + return; + } + + public void testFieldRefValidator_pass() + { + FieldRefValidator $l0; + unknown $stack1, $stack2; + + $l0 := @this: FieldRefValidator; + $stack1 = $l0.; + $stack2 = ; + + return; + } + + public void testFieldRefValidator_fail() + { + FieldRefValidator $l0; + unknown $stack1, $stack2; + + $l0 := @this: FieldRefValidator; + $stack1 = ; + $stack2 = $l0.; + + return; + } + +}