diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java b/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java index 07cf93cf5eb..88edf8a8e8e 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java @@ -33,6 +33,7 @@ import sootup.core.model.Body; import sootup.core.model.Position; import sootup.core.types.Type; +import sootup.core.types.VoidType; import sootup.core.util.Copyable; import sootup.core.util.printer.StmtPrinter; @@ -57,7 +58,11 @@ public Local(@Nonnull String name, @Nonnull Type type) { /** Constructs a JimpleLocal of the given name and type. */ public Local(@Nonnull String name, @Nonnull Type type, @Nonnull Position position) { this.name = name; - this.type = type; + if (type instanceof VoidType) { + throw new RuntimeException("Type should not be VoidType"); + } else { + this.type = type; + } this.position = position; } diff --git a/sootup.core/src/main/java/sootup/core/model/Body.java b/sootup.core/src/main/java/sootup/core/model/Body.java index cc397f95a90..3792b887b60 100644 --- a/sootup.core/src/main/java/sootup/core/model/Body.java +++ b/sootup.core/src/main/java/sootup/core/model/Body.java @@ -71,8 +71,7 @@ public class Body implements Copyable { new ValuesValidator(), new CheckInitValidator(), new CheckTypesValidator(), - new CheckVoidLocalesValidator(), - new CheckEscapingValidator()); + new CheckVoidLocalesValidator()); /** * Creates an body which is not associated to any method. @@ -89,7 +88,7 @@ private Body( this.graph = /* FIXME: [ms] make immutable when availabe */ new MutableBlockStmtGraph(stmtGraph).unmodifiableStmtGraph(); this.position = position; - checkInit(); + // checkInit(); } /** @@ -122,14 +121,6 @@ public int getLocalCount() { return locals.size(); } - private void runValidation(BodyValidator validator) { - final List exceptionList = new ArrayList<>(); - validator.validate(this, exceptionList); - if (!exceptionList.isEmpty()) { - throw exceptionList.get(0); - } - } - /** Verifies that a Value is not used in more than one place. */ // TODO: #535 implement validator public void validateValues() { runValidation(new // ValuesValidator());} @@ -141,9 +132,9 @@ private void runValidation(BodyValidator validator) { /** Verifies that each use in this Body has a def. */ // TODO: #535 implement validator public void validateUses() { runValidation(new // UsesValidator()); } - private void checkInit() { - runValidation(new CheckInitValidator()); - } + // private void checkInit() { + // runValidation(new CheckInitValidator(),); + // } /** Returns a backed chain of the locals declared in this Body. */ public Set getLocals() { @@ -279,9 +270,9 @@ public boolean isStmtBranchTarget(@Nonnull Stmt targetStmt) { return getStmtGraph().isStmtBranchTarget(targetStmt); } - public void validateIdentityStatements() { - runValidation(new IdentityStatementsValidator()); - } + // public void validateIdentityStatements() { + // runValidation(new IdentityStatementsValidator()); + // } /** Returns the first non-identity stmt in this body. */ @Nonnull diff --git a/sootup.core/src/main/java/sootup/core/validation/BodyValidator.java b/sootup.core/src/main/java/sootup/core/validation/BodyValidator.java index 30d1f2c4ef1..3c50827e75c 100644 --- a/sootup.core/src/main/java/sootup/core/validation/BodyValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/BodyValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; /** Implement this interface if you want to provide your own body Validator */ public interface BodyValidator { @@ -31,9 +32,9 @@ public interface BodyValidator { * Validates the given body and saves all validation errors in the given list. * * @param body the body to check - * @param exceptions the list of exceptions + * @param view the view */ - void validate(Body body, List exceptions); + List validate(Body body, View view); /** * Basic validators run essential checks and are run always if validate is called.
diff --git a/sootup.core/src/main/java/sootup/core/validation/CheckEscapingValidator.java b/sootup.core/src/main/java/sootup/core/validation/CheckEscapingValidator.java deleted file mode 100644 index 1973d840c07..00000000000 --- a/sootup.core/src/main/java/sootup/core/validation/CheckEscapingValidator.java +++ /dev/null @@ -1,49 +0,0 @@ -package sootup.core.validation; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 1997-2020 Raja Vallée-Rai, Linghui Luo - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.List; -import sootup.core.model.Body; - -public class CheckEscapingValidator implements BodyValidator { - - @Override - public void validate(Body body, List exception) { - - // TODO: check code from old soot below - - /* - * for (Unit u : body.getUnits()) { if (u instanceof Stmt) { Stmt stmt = (Stmt) u; if (stmt.containsInvokeExpr()) { - * InvokeExpr iexpr = stmt.getInvokeExpr(); SootMethodRef ref = iexpr.getMethodRef(); if (ref.name().contains("'") || - * ref.declaringClass().getName().contains("'")) { throw new ValidationException(stmt, - * "Escaped name in signature found"); } for (Type paramType : ref.parameterTypes()) { if - * (paramType.toString().contains("'")) { throw new ValidationException(stmt, "Escaped name in signature found"); } } } } - * } - */ - } - - @Override - public boolean isBasicValidator() { - return false; - } -} diff --git a/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java b/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java index d801585b227..b68a9ced297 100644 --- a/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java @@ -24,11 +24,12 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class CheckInitValidator implements BodyValidator { @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: #535 implement validator // check code copied from old soot @@ -41,6 +42,7 @@ public void validate(Body body, List exception) { * "Local variable $1 is not definitively defined at this point".replace("$1", l.getName()), "Warning: Local variable " + * l + " not definitely defined at " + s + " in " + body.getMethod(), false); } } } } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/CheckTypesValidator.java b/sootup.core/src/main/java/sootup/core/validation/CheckTypesValidator.java index efef2e6e2c6..1a8a301eb54 100644 --- a/sootup.core/src/main/java/sootup/core/validation/CheckTypesValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/CheckTypesValidator.java @@ -24,11 +24,12 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class CheckTypesValidator implements BodyValidator { @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: check code from old soot in the comment below /* * for (Unit u : body.getUnits()) { String errorSuffix = " at " + u + " in " + body.getMethod(); @@ -88,6 +89,7 @@ public void validate(Body body, List exception) { * body.getMethod())); } } } return; } exception.add(new ValidationException(stmt, "Warning: Bad types" + errorSuffix + * " in " + body.getMethod())); */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/CheckVoidLocalesValidator.java b/sootup.core/src/main/java/sootup/core/validation/CheckVoidLocalesValidator.java index 34885ec3d17..02c546ce28d 100644 --- a/sootup.core/src/main/java/sootup/core/validation/CheckVoidLocalesValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/CheckVoidLocalesValidator.java @@ -24,16 +24,18 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class CheckVoidLocalesValidator implements BodyValidator { @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * for (Local l : body.getLocals()) { if (l.getType() instanceof VoidType) { exception.add(new ValidationException(l, * "Local " + l + " in " + body.getMethod() + " defined with void type")); } } */ + return null; } @Override 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 2e6f8e57cc1..f7a2c07a04a 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, Linghui Luo, Markus Schmidt and others + * Copyright (C) 1997-2020 Raja Vallée-Rai, Christian Brüggemann, Markus Schmidt 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 @@ -22,14 +22,19 @@ * #L% */ +import java.util.ArrayList; import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class FieldRefValidator implements BodyValidator { - /** Checks the consistency of field references. */ + // Checks the consistency of field references. @Override - public void validate(Body body, List exceptions) { + 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; } @@ -54,6 +59,8 @@ public void validate(Body body, List exceptions) { * "Trying to get an instance field which is static: " + v)); } } else { throw new RuntimeException("unknown field ref"); * } } */ + + return validationException; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/IdentityStatementsValidator.java b/sootup.core/src/main/java/sootup/core/validation/IdentityStatementsValidator.java index 6d1e821f1da..4fb5d657285 100644 --- a/sootup.core/src/main/java/sootup/core/validation/IdentityStatementsValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/IdentityStatementsValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class IdentityStatementsValidator implements BodyValidator { @@ -36,9 +37,11 @@ public class IdentityStatementsValidator implements BodyValidator { *
  • param-references must precede all statements that are not themselves param-references or * this-references, if they occur at all * + * + * @return */ @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * SootMethod methodRef = body.getMethod(); if (methodRef.isAbstract()) { return; } @@ -57,6 +60,7 @@ public void validate(Body body, List exceptions) { * // @caughtexception statement foundNonThisOrParamIdentityStatement = true; } } else { // non-identity statement * foundNonThisOrParamIdentityStatement = true; } firstStatement = false; } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/IdentityValidator.java b/sootup.core/src/main/java/sootup/core/validation/IdentityValidator.java index c76bb0494ee..20090c42283 100644 --- a/sootup.core/src/main/java/sootup/core/validation/IdentityValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/IdentityValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; /** * This validator checks whether each ParameterRef and ThisRef is used exactly once. @@ -32,9 +33,13 @@ */ public class IdentityValidator implements BodyValidator { - /** Checks whether each ParameterRef and ThisRef is used exactly once. */ + /** + * Checks whether each ParameterRef and ThisRef is used exactly once. + * + * @return + */ @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * boolean hasThisLocal = false; int paramCount = body.getMethod().getParameterCount(); boolean[] parameterRefs = new @@ -57,6 +62,7 @@ public void validate(Body body, List exceptions) { * String.format("There is no parameter local for parameter number %d", i))); } } * */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/InvokeArgumentValidator.java b/sootup.core/src/main/java/sootup/core/validation/InvokeArgumentValidator.java index 478cd30a9df..ba7317dd0a8 100644 --- a/sootup.core/src/main/java/sootup/core/validation/InvokeArgumentValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/InvokeArgumentValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; /** * A basic validator that checks whether the length of the invoke statement's argument list matches @@ -34,13 +35,14 @@ public class InvokeArgumentValidator implements BodyValidator { @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * for (Unit u : body.getUnits()) { Stmt s = (Stmt) u; if (s.containsInvokeExpr()) { InvokeExpr iinvExpr = * s.getInvokeExpr(); SootMethod callee = iinvExpr.getMethod(); if (callee != null && iinvExpr.getArgCount() != * callee.getParameterCount()) { exceptions.add(new ValidationException(s, "Invalid number of arguments")); } } } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/JimpleTrapValidator.java b/sootup.core/src/main/java/sootup/core/validation/JimpleTrapValidator.java index 37d325af093..63bbe30bc52 100644 --- a/sootup.core/src/main/java/sootup/core/validation/JimpleTrapValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/JimpleTrapValidator.java @@ -24,19 +24,24 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; /** * This validator checks whether the jimple traps are correct. It does not perform the same checks * as {link sootup.validation.TrapsValidator} * - * @see JimpleTrapValidator#validate(Body, List) + * @see BodyValidator#validate(Body, View) * @author Marc Miltenberger */ public class JimpleTrapValidator implements BodyValidator { - /** Checks whether all Caught-Exception-References are associated to traps. */ + /** + * Checks whether all Caught-Exception-References are associated to traps. + * + * @return + */ @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * Set caughtUnits = new HashSet(); for (Trap trap : body.getTraps()) { @@ -52,6 +57,7 @@ public void validate(Body body, List exceptions) { * body.getMethod().getSignature() + " contains a caught exception reference," + * "but not a corresponding trap using this statement as handler")); } } } } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java b/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java index dc70ca2eb01..57808e72bf0 100644 --- a/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java @@ -22,38 +22,49 @@ * #L% */ +import java.util.ArrayList; import java.util.List; -import java.util.Set; import javax.annotation.Nonnull; -import sootup.core.jimple.basic.Local; import sootup.core.model.Body; +import sootup.core.views.View; public class LocalsValidator implements BodyValidator { - /** Verifies that each Local of getUses() and getDefs() belongs to this body's locals. */ + /** + * Verifies that each Local of getUses() and getDefs() belongs to this body's locals. + * + * @return + */ @Override - public void validate(@Nonnull Body body, @Nonnull List exception) { - final Set locals = body.getLocals(); + public List validate(@Nonnull Body body, @Nonnull View view) { + // TODO : Write tests + List exception = new ArrayList<>(); - body.getUses() - .parallelStream() - .filter(value -> value instanceof Local && !locals.contains(value)) - .forEach( - value -> - exception.add( - new ValidationException( - value, - "Local not in chain : " + value + " in " + body.getMethodSignature()))); + // final Set locals = body.getLocals(); + // + // body.getUses() + // .parallelStream() + // .filter(value -> value instanceof Local && !locals.contains(value)) + // .forEach( + // value -> + // exception.add( + // new ValidationException( + // value, + // "Local not in chain : " + value + " in " + + // body.getMethodSignature()))); + // + // body.getDefs() + // .parallelStream() + // .filter(value -> value instanceof Local && !locals.contains(value)) + // .forEach( + // value -> + // exception.add( + // new ValidationException( + // value, + // "Local not in chain : " + value + " in " + + // body.getMethodSignature()))); - body.getDefs() - .parallelStream() - .filter(value -> value instanceof Local && !locals.contains(value)) - .forEach( - value -> - exception.add( - new ValidationException( - value, - "Local not in chain : " + value + " in " + body.getMethodSignature()))); + return exception; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/MethodValidator.java b/sootup.core/src/main/java/sootup/core/validation/MethodValidator.java index bee729f7378..67e556c48dd 100644 --- a/sootup.core/src/main/java/sootup/core/validation/MethodValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/MethodValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class MethodValidator implements BodyValidator { @@ -33,9 +34,11 @@ public class MethodValidator implements BodyValidator { *
      *
    1. static initializer should have 'static' modifier *
    + * + * @return */ @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { // TODO: check copied code from old soot /* * SootMethod methodRef = body.getMethod(); if (methodRef.isAbstract()) { return; } if (methodRef.isStaticInitializer() @@ -43,6 +46,7 @@ public void validate(Body body, List exceptions) { * " should be static! Static initializer without 'static'('0x8') modifier" + * " will cause problem when running on android platform: " + "\" is not flagged correctly wrt/ static\"!")); } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/NewValidator.java b/sootup.core/src/main/java/sootup/core/validation/NewValidator.java index 6d7f94904e6..36c524f7270 100644 --- a/sootup.core/src/main/java/sootup/core/validation/NewValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/NewValidator.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 @@ -22,95 +22,158 @@ * #L% */ +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import sootup.core.graph.StmtGraph; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.types.ReferenceType; +import sootup.core.types.UnknownType; +import sootup.core.views.View; -/** - * A relatively simple validator. It tries to check whether after each new-expression-statement - * there is a corresponding call to the <init> method before a use or the end of the method. - * - * @author Marc Miltenberger - * @author Steven Arzt - */ public class NewValidator implements BodyValidator { - private static final String errorMsg = + private static final String ERROR_MSG = "There is a path from '%s' to the usage '%s' where does not get called in between."; public static boolean MUST_CALL_CONSTRUCTOR_BEFORE_RETURN = false; - /** Checks whether after each new-instruction a constructor call follows. */ + // Checks whether after each new-instruction a constructor call follows. @Override - public void validate(Body body, List exceptions) { - // TODO: check copied code from old soot - /* - * UnitGraph g = new BriefUnitGraph(body); for (Unit u : body.getUnits()) { if (u instanceof JAssignStmt) { JAssignStmt - * assign = (JAssignStmt) u; - * - * // First seek for a JNewExpr. if (assign.getRightOp() instanceof JNewExpr) { if (!(assign.getLeftOp().getType() - * instanceof RefType)) { exceptions.add(new ValidationException(u, - * "A new-expression must be used on reference type locals", - * String.format("Body of methodRef %s contains a new-expression, which is assigned to a non-reference local", - * body.getMethod().getSignature()))); return; } - * - * // We search for a JSpecialInvokeExpr on the local. LinkedHashSet locals = new LinkedHashSet(); - * locals.add((Local) assign.getLeftOp()); - * - * checkForInitializerOnPath(g, assign, exceptions); } } } - * - * } - * - * - *

    Checks whether all pathes from start to the end of the methodRef have a call to the <init> methodRef in - * between.

    $r0 = new X;
    ...
    specialinvoke $r0.()>; //validator checks whether this - * statement is missing

    Regarding aliasingLocals:
    The first local in the set is always the local - * on the LHS of the new-expression-assignment (called: original local; in the example $r0).

    - * - * @param g the unit graph of the methodRef - * - * @param exception the list of all collected exceptions - * - * @return true if a call to a <init>-Method has been found on this way. - * - * private boolean checkForInitializerOnPath(UnitGraph g, AssignStmt newStmt, List exception) { - * List workList = new ArrayList(); Set doneSet = new HashSet(); workList.add(newStmt); - * - * Set aliasingLocals = new HashSet(); aliasingLocals.add((Local) newStmt.getLeftOp()); - * - * while (!workList.isEmpty()) { Stmt curStmt = (Stmt) workList.remove(0); if (!doneSet.add(curStmt)) { continue; } if - * (!newStmt.equals(curStmt)) { if (curStmt.containsInvokeExpr()) { InvokeExpr expr = curStmt.getInvokeExpr(); if - * (expr.getMethod().isConstructor()) { if (!(expr instanceof SpecialInvokeExpr)) { exception.add(new - * ValidationException(curStmt, " methodRef calls may only be used with specialinvoke.")); // At least we found an - * initializer, so we return true... return true; } if (!(curStmt instanceof InvokeStmt)) { exception.add(new - * ValidationException(curStmt, " methods may only be called with invoke statements.")); // At least we found an - * initializer, so we return true... return true; } - * - * SpecialInvokeExpr invoke = (SpecialInvokeExpr) expr; if (aliasingLocals.contains(invoke.getBase())) { // We are happy - * now, continue the loop and check other paths continue; } } } - * - * // We are still in the loop, so this was not the constructor call we // were looking for boolean creatingAlias = - * false; if (curStmt instanceof AssignStmt) { AssignStmt assignCheck = (AssignStmt) curStmt; if - * (aliasingLocals.contains(assignCheck.getRightOp())) { if (assignCheck.getLeftOp() instanceof Local) { // A new alias - * is created. aliasingLocals.add((Local) assignCheck.getLeftOp()); creatingAlias = true; } } Local originalLocal = - * aliasingLocals.iterator().next(); if (originalLocal.equals(assignCheck.getLeftOp())) { // In case of dead assignments: - * - * // Handles cases like // $r0 = new x; // $r0 = null; - * - * // But not cases like // $r0 = new x; // $r1 = $r0; // $r1 = null; // Because we check for the original local - * continue; } else { // Since the local on the left hand side gets overwritten // even if it was aliasing with our - * original local, // now it does not any more... aliasingLocals.remove(assignCheck.getLeftOp()); } } - * - * if (!creatingAlias) { for (ValueBox box : curStmt.getUseBoxes()) { Value used = box.getValue(); if - * (aliasingLocals.contains(used)) { // The current unit uses one of the aliasing locals, but // there was no initializer - * in between. // However, when creating such an alias, the use is okay. exception.add(new ValidationException(newStmt, - * String.format(errorMsg, newStmt, curStmt))); return false; } } } } // Enqueue the successors List successors = - * g.getSuccsOf(curStmt); if (successors.isEmpty() && MUST_CALL_CONSTRUCTOR_BEFORE_RETURN) { // This means that we are - * e.g. at the end of the methodRef // There was no call on our way... exception.add(new - * ValidationException(newStmt, String.format(errorMsg, newStmt, curStmt))); return false; } workList.addAll(successors); - * } return true; - * - * - */ + public List validate(Body body, View view) { + + List exceptions = new ArrayList<>(); + + StmtGraph g = body.getStmtGraph(); + for (Stmt u : body.getStmts()) { + if (u instanceof JAssignStmt) { + JAssignStmt assign = (JAssignStmt) u; + + // First seek for a JNewExpr. + if (assign.getRightOp() instanceof JNewExpr) { + if (!((assign.getLeftOp().getType() instanceof ReferenceType) + || assign.getLeftOp().getType() instanceof UnknownType)) { + exceptions.add( + new ValidationException( + assign.getLeftOp(), + String.format( + "Body of methodRef %s contains a new-expression, which is assigned to a non-reference local", + body.getMethodSignature()))); + return exceptions; + } + + checkForInitializerOnPath(g, assign, exceptions); + } + } + } + return exceptions; + } + + private boolean checkForInitializerOnPath( + StmtGraph g, JAssignStmt newStmt, List exception) { + List workList = new ArrayList<>(); + Set doneSet = new HashSet<>(); + workList.add(newStmt); + + Set aliasingLocals = new HashSet<>(); + aliasingLocals.add((Local) newStmt.getLeftOp()); + + while (!workList.isEmpty()) { + Stmt curStmt = workList.remove(0); + if (!doneSet.add(curStmt)) { + continue; + } + if (!newStmt.equals(curStmt)) { + if (curStmt.containsInvokeExpr()) { + AbstractInvokeExpr expr = curStmt.getInvokeExpr(); + if (!(expr instanceof JSpecialInvokeExpr)) { + exception.add( + new ValidationException( + curStmt.getInvokeExpr(), + " methodRef calls may only be used with specialinvoke.")); // At least we + // found an initializer, so we return true... + return true; + } + if (!(curStmt instanceof JInvokeStmt)) { + exception.add( + new ValidationException( + curStmt.getInvokeExpr(), + " methods may only be called with invoke statements.")); // At least we + // found an initializer, so we return true... + return true; + } + + JSpecialInvokeExpr invoke = (JSpecialInvokeExpr) expr; + if (aliasingLocals.contains(invoke.getBase())) { + // We are happy now,continue the loop and check other paths + continue; + } + } + + // We are still in the loop, so this was not the constructor call we were looking for + boolean creatingAlias = false; + if (curStmt instanceof JAssignStmt) { + JAssignStmt assignCheck = (JAssignStmt) curStmt; + if (aliasingLocals.contains(assignCheck.getRightOp())) { + if (assignCheck.getLeftOp() instanceof Local) { + // A new alias is created. + aliasingLocals.add((Local) assignCheck.getLeftOp()); + creatingAlias = true; + } + } + Local originalLocal = aliasingLocals.iterator().next(); + if (originalLocal.equals(assignCheck.getLeftOp())) { // In case of dead assignments: + + // Handles cases like // $r0 = new x; // $r0 = null; + + // But not cases like // $r0 = new x; // $r1 = $r0; // $r1 = null; // Because we check + // for the original local + continue; + } else { + // Since the local on the left hand side gets overwritten + // even if it was aliasing with our original local, + // now it does not any more... + aliasingLocals.remove(assignCheck.getLeftOp()); + } + } + + if (!creatingAlias) { + for (Value box : curStmt.getUses()) { + if (aliasingLocals.contains(box)) { + // The current unit uses one of the aliasing locals, but + // there was no initializer in between. + // However, when creating such an alias, the use is okay. + exception.add( + new ValidationException( + newStmt.getLeftOp(), String.format(ERROR_MSG, newStmt, curStmt))); + return false; + } + } + } + } + // Enqueue the successors + List successors = g.successors(curStmt); + if (successors.isEmpty() && MUST_CALL_CONSTRUCTOR_BEFORE_RETURN) { + // This means that we are e.g.at the end of + // the methodRef // There was no call + // on our way... + exception.add( + new ValidationException( + newStmt.getLeftOp(), String.format(ERROR_MSG, newStmt, curStmt))); + return false; + } + workList.addAll(successors); + } + return true; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/ReturnStatementsValidator.java b/sootup.core/src/main/java/sootup/core/validation/ReturnStatementsValidator.java deleted file mode 100644 index e76f5922c58..00000000000 --- a/sootup.core/src/main/java/sootup/core/validation/ReturnStatementsValidator.java +++ /dev/null @@ -1,63 +0,0 @@ -package sootup.core.validation; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 1997-2020 Raja Vallée-Rai, Markus Schmidt 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 - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.List; -import sootup.core.model.Body; - -public class ReturnStatementsValidator implements BodyValidator { - - /** - * Checks the following invariants on this Jimple body: - * - *
      - *
    1. this-references may only occur in instance methods - *
    2. this-references may only occur as the first statement in a method, if they occur at all - *
    3. param-references must precede all statements that are not themselves param-references or - * this-references, if they occur at all - *
    - */ - @Override - public void validate(Body body, List exceptions) { - - // TODO: check copied code from old soot - /* - * // Checks that this Jimple body actually contains a return statement for (Unit u : body.getUnits()) { if ((u - * instanceof JReturnStmt) || (u instanceof JReturnVoidStmt) || (u instanceof JRetStmt) || (u instanceof JThrowStmt)) { - * return; } } - * - * // A methodRef can have an infinite loop // and no return statement: // // public class Infinite { // public static - * void main(String[] args) { // int i = 0; while (true) {i += 1;} } } // // Only check that the execution cannot fall - * off the code. Unit last = body.getUnits().getLast(); if (last instanceof JGotoStmt|| last instanceof JThrowStmt) { - * return; } - * - * exceptions.add(new ValidationException(body.getMethod(), "The methodRef does not contain a return statement", - * "Body of methodRef " + body.getMethod().getSignature() + " does not contain a return statement")); - */ - } - - @Override - public boolean isBasicValidator() { - return true; - } -} diff --git a/sootup.core/src/main/java/sootup/core/validation/StmtsValidator.java b/sootup.core/src/main/java/sootup/core/validation/StmtsValidator.java index 2e88a1608d9..a80c86c109d 100644 --- a/sootup.core/src/main/java/sootup/core/validation/StmtsValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/StmtsValidator.java @@ -24,12 +24,19 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class StmtsValidator implements BodyValidator { - /** Verifies that the Units of this Body all point to a Unit contained within this body. */ + /** + * Verifies that the Units of this Body all point to a Unit contained within this body. + * + * @return + */ @Override - public void validate(Body body, List exception) {} + public List validate(Body body, View view) { + return null; + } @Override public boolean isBasicValidator() { diff --git a/sootup.core/src/main/java/sootup/core/validation/TrapsValidator.java b/sootup.core/src/main/java/sootup/core/validation/TrapsValidator.java index 5e9093a4fd4..d13e9a4e189 100644 --- a/sootup.core/src/main/java/sootup/core/validation/TrapsValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/TrapsValidator.java @@ -24,12 +24,17 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class TrapsValidator implements BodyValidator { - /** Verifies that the begin, end and handler units of each trap are in this body. */ + /** + * Verifies that the begin, end and handler units of each trap are in this body. + * + * @return + */ @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: check code from old soot below /* @@ -44,6 +49,7 @@ public void validate(Body body, List exception) { * if (!units.contains(t.getHandlerUnit())) { exception.add(new ValidationException(t.getHandlerUnit(), * "handler not in chain" + " in " + body.getMethod())); } } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/TypesValidator.java b/sootup.core/src/main/java/sootup/core/validation/TypesValidator.java index 4da9a64818b..d7559fc6f90 100644 --- a/sootup.core/src/main/java/sootup/core/validation/TypesValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/TypesValidator.java @@ -24,6 +24,7 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; /** * Checks whether the types used for locals, method parameters, and method return values are allowed @@ -32,7 +33,7 @@ public class TypesValidator implements BodyValidator { @Override - public void validate(Body body, List exceptions) { + public List validate(Body body, View view) { /* * SootMethod methodRef = body.getMethod(); * @@ -45,6 +46,7 @@ public void validate(Body body, List exceptions) { * exceptions.add(new ValidationException(l, "Local type not allowed in final code: " + t, "(" + methodRef + * ") local type not allowed in final code: " + t + " local: " + l)); } } */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/UsesValidator.java b/sootup.core/src/main/java/sootup/core/validation/UsesValidator.java index 9d1f2e32008..849beb763a0 100644 --- a/sootup.core/src/main/java/sootup/core/validation/UsesValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/UsesValidator.java @@ -24,12 +24,17 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class UsesValidator implements BodyValidator { - /** Verifies that each use in this Body has a def. */ + /** + * Verifies that each use in this Body has a def. + * + * @return + */ @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: auto generated stub /* * // Conservative validation of uses: add edges to exception handlers // even if they are not reachable. // // class C { @@ -61,6 +66,7 @@ public void validate(Body body, List exception) { * private boolean graphEdgesAreValid(UnitGraph g, Unit u) { /* for (Unit p : g.getPredsOf(u)) { if * (!g.getSuccsOf(p).contains(u)) { return false; } } return true; */ + return null; } @Override diff --git a/sootup.core/src/main/java/sootup/core/validation/ValuesValidator.java b/sootup.core/src/main/java/sootup/core/validation/ValuesValidator.java index 5595e0cbebc..2787482fb04 100644 --- a/sootup.core/src/main/java/sootup/core/validation/ValuesValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/ValuesValidator.java @@ -24,12 +24,17 @@ import java.util.List; import sootup.core.model.Body; +import sootup.core.views.View; public class ValuesValidator implements BodyValidator { - /** Verifies that a Value is not used in more than one place. */ + /** + * Verifies that a Value is not used in more than one place. + * + * @return + */ @Override - public void validate(Body body, List exception) { + public List validate(Body body, View view) { // TODO: check code from old soot below /* * Set set = newSetFromMap(new IdentityHashMap()); @@ -40,6 +45,7 @@ public void validate(Body body, List exception) { * * for (Unit u : body.getUnits()) { System.err.println(u); } } */ + return null; } @Override diff --git a/sootup.java.bytecode/pom.xml b/sootup.java.bytecode/pom.xml index 2cc4ca5e6c9..e3a1e875d14 100644 --- a/sootup.java.bytecode/pom.xml +++ b/sootup.java.bytecode/pom.xml @@ -16,12 +16,12 @@ org.soot-oss sootup.core - 1.1.2-SNAPSHOT + ${project.version} org.soot-oss sootup.java.core - 1.1.2-SNAPSHOT + ${project.version} org.ow2.asm @@ -38,7 +38,7 @@ dex2jar 2.4.6 - + diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/JimpleSemanticsChecker.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/JimpleSemanticsChecker.java new file mode 100644 index 00000000000..92dc217e60e --- /dev/null +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/JimpleSemanticsChecker.java @@ -0,0 +1,69 @@ +package sootup.java.bytecode.interceptors; +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2023 Markus Schmidt + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ +import java.util.List; +import javax.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sootup.core.model.Body; +import sootup.core.transform.BodyInterceptor; +import sootup.core.validation.ValidationException; +import sootup.core.views.View; + +/** + * This Interceptor executes validations on Jimple semantics + * + *

    e.g. like a Local must be assigned before its use + */ +public abstract class JimpleSemanticsChecker implements BodyInterceptor { + + private static final Logger logger = LoggerFactory.getLogger(JimpleSemanticsChecker.class); + + protected List validate( + @Nonnull Body.BodyBuilder builder, @Nonnull View view) { + // FIXME: implement + throw new UnsupportedOperationException("List of Validators is not incorporated yet."); + } + + @Override + public abstract void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view); + + public static class LoggingJimpleChecker extends JimpleSemanticsChecker { + + @Override + public void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view) { + final List exceptions = validate(builder, view); + for (ValidationException validationException : exceptions) { + logger.warn(validationException.getMessage()); + } + } + } + + public static class ThrowingJimpleChecker extends LoggingJimpleChecker { + + @Override + public void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view) { + super.interceptBody(builder, view); + throw new IllegalStateException("There are semantic errors in the Jimple - see warn log."); + } + } +} diff --git a/sootup.java.sourcecode/pom.xml b/sootup.java.sourcecode/pom.xml index 56f40ea86d3..669c7f133f4 100644 --- a/sootup.java.sourcecode/pom.xml +++ b/sootup.java.sourcecode/pom.xml @@ -69,12 +69,12 @@ org.soot-oss sootup.core - 1.1.2-SNAPSHOT + ${project.version} org.soot-oss sootup.java.core - 1.1.2-SNAPSHOT + ${project.version} diff --git a/sootup.tests/pom.xml b/sootup.tests/pom.xml index fdf3c29f384..fd266c24d67 100644 --- a/sootup.tests/pom.xml +++ b/sootup.tests/pom.xml @@ -34,12 +34,23 @@ sootup.java.sourcecode ${project.version} + + org.soot-oss + sootup.jimple.parser + ${project.version} + org.soot-oss sootup.callgraph ${project.version} - + + org.soot-oss + sootup.jimple.parser + 1.1.2-SNAPSHOT + test + + diff --git a/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java b/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java new file mode 100644 index 00000000000..ebd12db02f3 --- /dev/null +++ b/sootup.tests/src/test/java/sootup/tests/validator/NewValidatorTest.java @@ -0,0 +1,114 @@ +package sootup.tests.validator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +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 sootup.core.model.SootClass; +import sootup.core.model.SourceType; +import sootup.core.signatures.PackageName; +import sootup.core.types.ClassType; +import sootup.core.validation.NewValidator; +import sootup.core.validation.ValidationException; +import sootup.jimple.parser.JimpleAnalysisInputLocation; +import sootup.jimple.parser.JimpleView; + +public class NewValidatorTest { + + NewValidator validator; + JimpleView view; + Collection> classes; + + @Before + public void Setup() { + + validator = new NewValidator(); + + ClassType classTypeNewValidator = + new ClassType() { + @Override + public boolean isBuiltInClass() { + return false; + } + + @Override + public String getFullyQualifiedName() { + return "jimple.NewValidator"; + } + + @Override + public String getClassName() { + return "NewValidator"; + } + + @Override + public PackageName getPackageName() { + return new PackageName("jimple"); + } + }; + + String classPath = "src/test/resources/validator/jimple"; + JimpleAnalysisInputLocation jimpleInputLocation = + new JimpleAnalysisInputLocation(Paths.get(classPath), SourceType.Application); + + view = new JimpleView(jimpleInputLocation); + final Optional> classSource1 = view.getClass(classTypeNewValidator); + assertFalse(classSource1.isPresent()); + + classes = new HashSet<>(); // Set to track the classes to check + + for (SootClass aClass : view.getClasses()) { + if (!aClass.isLibraryClass()) { + classes.add(aClass); + } + } + } + + @Test + public void testNewValidatorSuccess() { + List validationExceptions_success; + + validationExceptions_success = + validator.validate( + classes.stream() + .filter(c -> c.getType().getClassName().equals("NewValidator")) + .findFirst() + .get() + .getMethods() + .stream() + .filter(m -> m.getName().equals("newValidator_pass")) + .map(m -> m.getBody()) + .findFirst() + .get(), + view); + + assertEquals(0, validationExceptions_success.size()); + } + + @Test + public void testNewValidatorFailure() { + List validationExceptions_fail; + + validationExceptions_fail = + validator.validate( + classes.stream() + .filter(c -> c.getType().getClassName().equals("NewValidator")) + .findFirst() + .get() + .getMethods() + .stream() + .filter(m -> m.getName().equals("newValidator_fail")) + .map(m -> m.getBody()) + .findFirst() + .get(), + view); + + assertEquals(1, validationExceptions_fail.size()); + } +} diff --git a/sootup.tests/src/test/resources/validator/jimple/NewValidator.jimple b/sootup.tests/src/test/resources/validator/jimple/NewValidator.jimple new file mode 100644 index 00000000000..f8aea86b66a --- /dev/null +++ b/sootup.tests/src/test/resources/validator/jimple/NewValidator.jimple @@ -0,0 +1,34 @@ +public super class NewValidator extends java.lang.Object +{ + public void newValidator_pass() + { + java.lang.String[] $l0; + unknown $l1, $stack2, $stack3, $stack4; + + $l0 := @parameter0: java.lang.String[]; + $stack2 = new NewValidator_pass; + specialinvoke $stack2.()>(); + $l1 = $stack2; + $stack4 = ; + $stack3 = $l1.; + virtualinvoke $stack4.($stack3); + + return; + } + + public void newValidator_fail() + { + java.lang.String[] $l0; + unknown $l1, $stack2, $stack3, $stack4; + + $l0 := @parameter0: java.lang.String[]; + $stack2 = new NewValidator_fail; + + $l1 = $stack2; + $stack4 = ; + $stack3 = $l1.; + virtualinvoke $stack4.($stack3); + + return; + } +} \ No newline at end of file