Skip to content

Commit

Permalink
Refactored NewValidator.java to work with Sootup.
Browse files Browse the repository at this point in the history
Deleting CheckEscapingValidator.java and ReturnStatementsValidator.java.
  • Loading branch information
akshitad11 committed Oct 30, 2023
1 parent 647da14 commit 1fb79eb
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 216 deletions.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
public class NewKeywordValidator {

int x = 5;

public static void main(String[] args) {
NewKeywordValidator myObj = new NewKeywordValidator();
System.out.println(myObj.x);
}
}
11 changes: 9 additions & 2 deletions sootup.core/src/main/java/sootup/core/jimple/basic/Local.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -55,9 +56,15 @@ 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) {
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;
}

Expand Down
3 changes: 1 addition & 2 deletions sootup.core/src/main/java/sootup/core/model/Body.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,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.
Expand Down

This file was deleted.

239 changes: 139 additions & 100 deletions sootup.core/src/main/java/sootup/core/validation/NewValidator.java
Original file line number Diff line number Diff line change
@@ -1,116 +1,155 @@
package sootup.core.validation;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* 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
* 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
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import java.util.List;
import java.util.*;
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;

/**
* A relatively simple validator. It tries to check whether after each new-expression-statement
* there is a corresponding call to the &lt;init&gt; 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 =
"There is a path from '%s' to the usage '%s' where <init> 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<ValidationException> 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<Local> locals = new LinkedHashSet<Local>();
* locals.add((Local) assign.getLeftOp());
*
* checkForInitializerOnPath(g, assign, exceptions); } } }
*
* }
*
*
* <p> Checks whether all pathes from start to the end of the methodRef have a call to the &lt;init&gt; methodRef in
* between. </p> <code> $r0 = new X;<br> ...<br> specialinvoke $r0.<X: void <init>()>; //validator checks whether this
* statement is missing </code> <p> Regarding <i>aliasingLocals</i>:<br> The first local in the set is always the local
* on the LHS of the new-expression-assignment (called: original local; in the example <code>$r0</code>). </p>
*
* @param g the unit graph of the methodRef
*
* @param exception the list of all collected exceptions
*
* @return true if a call to a &lt;init&gt;-Method has been found on this way.
*
* private boolean checkForInitializerOnPath(UnitGraph g, AssignStmt newStmt, List<ValidationException> exception) {
* List<Unit> workList = new ArrayList<Unit>(); Set<Unit> doneSet = new HashSet<Unit>(); workList.add(newStmt);
*
* Set<Local> aliasingLocals = new HashSet<Local>(); 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, "<init> 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, "<init> 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<Unit> 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 <init> call on our way... exception.add(new
* ValidationException(newStmt, String.format(errorMsg, newStmt, curStmt))); return false; } workList.addAll(successors);
* } return true;
*
*
*/

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;
}

// We search for a JSpecialInvokeExpr on the local.
LinkedHashSet<Local> locals = new LinkedHashSet<Local>();
locals.add((Local) assign.getLeftOp());

checkForInitializerOnPath(g, assign, exceptions);
}
}
}
}

private boolean checkForInitializerOnPath(
StmtGraph g, JAssignStmt newStmt, List<ValidationException> exception) {
List<Stmt> workList = new ArrayList<Stmt>();
Set<Stmt> doneSet = new HashSet<Stmt>();
workList.add(newStmt);

Set<Local> aliasingLocals = new HashSet<Local>();
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()) {
AbstractInvokeExpr expr = curStmt.getInvokeExpr();
if (!(expr instanceof JSpecialInvokeExpr)) {
exception.add(
new ValidationException(
curStmt.getInvokeExpr(),
"<init> 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(),
"<init> 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 aliasis 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,
String.format(errorMsg, 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 <init> call
// on our way...
exception.add(
new ValidationException(
newStmt.getLeftOp(), String.format(errorMsg, newStmt, curStmt)));
return false;
}
workList.addAll(successors);
}
}
}
return true;
}

@Override
Expand Down
Loading

0 comments on commit 1fb79eb

Please sign in to comment.