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

Fix JimplePrinter escaping to work like (old) Soot #647

Draft
wants to merge 14 commits into
base: develop
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public GraphBasedCallGraph() {
signatureToVertex = new HashMap<>();
}

public GraphBasedCallGraph(
protected GraphBasedCallGraph(
@Nonnull DefaultDirectedGraph<Vertex, Edge> graph,
@Nonnull Map<MethodSignature, Vertex> signatureToVertex) {
this.graph = graph;
Expand Down Expand Up @@ -181,9 +181,13 @@ public String exportAsDot() {
Vertex targetVertex = graph.getEdgeTarget(edge);
dotFormatBuilder
.append("\t")
.append("\"" + sourceVertex.methodSignature + "\"")
.append("\"")
.append(sourceVertex.methodSignature)
.append("\"")
.append(" -> ")
.append("\"" + targetVertex.methodSignature + "\"")
.append("\"")
.append(targetVertex.methodSignature)
.append("\"")
.append(";\n");
});

Expand All @@ -207,7 +211,8 @@ public MutableCallGraph copy() {
@Nonnull
protected Vertex vertexOf(@Nonnull MethodSignature method) {
Vertex methodVertex = signatureToVertex.get(method);
Preconditions.checkNotNull(methodVertex, "Node for " + method + " has not been added yet");
Preconditions.checkNotNull(
methodVertex, "Node for " + method + " does not exist in this CallGraph.");
return methodVertex;
}

Expand Down
42 changes: 15 additions & 27 deletions sootup.core/src/main/java/sootup/core/util/StringTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,15 @@ public class StringTools {

/** Returns fromString, but with non-isalpha() characters printed as <code>'\\unnnn'</code>. */
public static String getEscapedStringOf(String fromString) {
// TODO: [ms] possible performance+ maybe(!) work on .charAt(..) instead of .toCharArray)(..)
char[] fromStringArray = fromString.toCharArray();

// TODO: [ms] this makes the exported jimple platform dependent? improve!
char cr = lineSeparator.charAt(0);
char lf = lineSeparator.length() == 2 ? lineSeparator.charAt(1) : cr;

// find if there is (find the first) a need to escape
// find the first char that has to be escaped
int firstNonAlphaPos = -1;
final int size = fromStringArray.length;
for (int j = 0; j < size; j++) {
char ch = fromStringArray[j];
final boolean isPrintableAscii = (ch >= 32 && ch <= 126);
if (!((isPrintableAscii || ch == cr || ch == lf) && ch != '\\')) {
if (!((isPrintableAscii || ch == '\r' || ch == '\n') && ch != '\\')) {
firstNonAlphaPos = j;
break;
}
Expand All @@ -65,7 +60,7 @@ public static String getEscapedStringOf(String fromString) {
j < fromStringArrayLength;
j++) {
char ch = fromStringArray[j];
if (((ch >= 32 && ch <= 126) || ch == cr || ch == lf) && ch != '\\') {
if (((ch >= 32 && ch <= 126) || ch == '\r' || ch == '\n') && ch != '\\') {
sb.append(ch);
} else {
sb.append(getUnicodeStringFromChar(ch));
Expand All @@ -75,62 +70,55 @@ public static String getEscapedStringOf(String fromString) {
return sb.toString();
}

/** Convenience field storing the system line separator. */
public static final String lineSeparator = System.getProperty("line.separator");

/**
* Returns fromString, but with certain characters printed as if they were in a Java string
* literal. Used by StringConstant.toString()
*/
public static String getQuotedStringOf(String fromString, boolean needsQuotes) {
public static String getQuotedStringOf(String fromString, boolean neededQuotes) {
// We definitely need fromString.length + 2, but let's have some
// additional space
StringBuilder builder = new StringBuilder(fromString.length() + 20);
builder.append("\"");
builder.append('\'');
for (int i = 0; i < fromString.length(); i++) {
char ch = fromString.charAt(i);
if (ch == '\\') {
builder.append("\\\\");
needsQuotes = true;
neededQuotes = true;
} else if (ch == '\'') {
builder.append("\\\'");
needsQuotes = true;
builder.append("\\'");
neededQuotes = true;
} else if (ch == '\"') {
builder.append("\\\"");
needsQuotes = true;
neededQuotes = true;
} else if (ch == '\n') {
builder.append("\\n");
needsQuotes = true;
neededQuotes = true;
} else if (ch == '\t') {
builder.append("\\t");
needsQuotes = true;
neededQuotes = true;
}
/*
* 04.04.2006 mbatch added handling of \r, as compilers throw error if unicode
*/
else if (ch == '\r') {
builder.append("\\r");
needsQuotes = true;
neededQuotes = true;
}
/*
* 10.04.2006 Nomait A Naeem added handling of \f, as compilers throw error if unicode
*/
else if (ch == '\f') {
builder.append("\\f");
needsQuotes = true;
neededQuotes = true;
} else if (ch >= 32 && ch <= 126 /* is printable ascii */) {
builder.append(ch);
// TODO: [ms] adapt this list to add quotes in cases where it is necessary
if (ch == ' ' || ch == ';' || ch == '/') {
needsQuotes = true;
}
} else {
builder.append(getUnicodeStringFromChar(ch));
}
}

return needsQuotes
? builder.append('"').toString()
return neededQuotes
? builder.append('\'').toString()
: builder.subSequence(1, builder.length()).toString();
}

Expand Down
13 changes: 13 additions & 0 deletions sootup.core/src/main/java/sootup/core/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -36,6 +37,8 @@
import javax.annotation.Nullable;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import sootup.core.jimple.basic.EquivTo;
import sootup.core.model.Body;
Expand All @@ -46,6 +49,16 @@
/** @author Linghui Luo */
public class Utils {

void exportAsJimpleFile(@Nonnull SootClass<?> c, @Nonnull String baseDir){
try {
String printClass = c.print();
File file = new File(baseDir + c.getName().replace('.', '/') + ".jimple");
FileUtils.writeStringToFile(file, printClass, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Nullable
Path compileJavaOTF(String className, String javaSourceContent) {
File sourceFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void typeSignature(@Nonnull Type type) {
((ArrayType) type).toString(this);
} else {
// primitive types: there should be no need to escape sth
output.append(type.toString());
output.append(type);
}
} else {
output.append(Jimple.escape(type.toString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,13 @@ public void printTo(SootClass<?> cl, PrintWriter out, LabeledStmtPrinter printer
*/

EnumSet<ClassModifier> modifiers = EnumSet.copyOf(cl.getModifiers());
// remove unwanted modifier combinations
// remove unwanted modifier combinations from print
if (cl.isInterface() && ClassModifier.isAbstract(modifiers)) {
modifiers.remove(ClassModifier.ABSTRACT);
}
modifiers.remove(ClassModifier.SUPER);
modifiers.remove(ClassModifier.MODULE);

if (modifiers.size() != 0) {
printer.modifier(ClassModifier.toString(modifiers));
printer.literal(" ");
Expand Down Expand Up @@ -226,7 +229,7 @@ public void printTo(SootClass<?> cl, PrintWriter out, LabeledStmtPrinter printer
out.println();
}

out.println(printer.toString());
out.println(printer);
}

private void printMethods(SootClass<?> cl, LabeledStmtPrinter printer) {
Expand All @@ -239,17 +242,19 @@ private void printMethods(SootClass<?> cl, LabeledStmtPrinter printer) {
while (methodIt.hasNext()) {
SootMethod method = (SootMethod) methodIt.next();

printer.handleIndent();
method.toString(printer);

if (method.hasBody()) {
Body body = method.getBody();
// print method's full signature information
method.toString(printer);
printer.newline();
incJimpleLnNum();
printBody(body, printer);

} else {
printer.handleIndent();
method.toString(printer);
printer.literal(";");
printer.newline();
incJimpleLnNum();
}

Expand Down Expand Up @@ -343,7 +348,7 @@ private void printStmts(StmtGraph<?> stmtGraph, LabeledStmtPrinter printer) {

final boolean currentStmtHasLabel = labels.get(currentStmt) != null;
if (previousStmt.branches()
|| stmtGraph.predecessors(currentStmt).size() != 1
|| stmtGraph.predecessors(currentStmt).size() > 1
|| previousStmt.getExpectedSuccessorCount() == 0
|| currentStmtHasLabel) {
printer.newline();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@
* #L%
*/

import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.annotation.Nonnull;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.jimple.javabytecode.stmt.JSwitchStmt;
import sootup.core.types.ClassType;
import sootup.core.types.Type;
import sootup.core.util.StringTools;

/**
* StmtPrinter implementation for normal (full) Jimple for OldSoot
Expand All @@ -35,18 +41,112 @@
*/
public class LegacyJimplePrinter extends NormalStmtPrinter {

// source:
// https://github.com/soot-oss/soot/blob/1ad74494974165e8b5f2286c90f218a00eadc243/eclipse/ca.mcgill.sable.soot/src/ca/mcgill/sable/soot/editors/JimpleScanner.java
Set<String> soot_jimple_keywords =
ImmutableSet.of(
"ignored",
"abstract",
"final",
"native",
"public",
"protected",
"private",
"static",
"synchronized",
"transient",
"volatile",
"class",
"interface",
"void",
"boolean",
"byte",
"short",
"char",
"int",
"long",
"float",
"double",
"null_type",
"unknown",
"extends",
"implements",
"breakpoint",
"case",
"catch",
"cmp",
"cmpg",
"cmpl",
"default",
"entermonitor",
"exitmonitor",
"goto",
"if",
"instanceof",
"interfaceinvoke",
"lengthof",
"lookupswitch",
"neg",
"new",
"newarray",
"newmultiarray",
"nop",
"ret",
"return",
"specialinvoke",
"staticinvoke",
"tableswitch",
"throw",
"throws",
"virtualinvoke",
"null",
"from",
"to",
"with",
"annotation",
"enum");

public LegacyJimplePrinter() {
super();
}

@Nonnull
protected String sootEscape(String str) {
if (str.length() == 0) {
return "''";
}
return StringTools.getQuotedStringOf(str, soot_jimple_keywords.contains(str));
}

@Override
void enableImports(boolean enable) {
if (enable) {
throw new RuntimeException(
throw new IllegalArgumentException(
"Imports are not supported in Legacy Jimple: don't enable UseImports");
}
}

@Override
public void typeSignature(@Nonnull Type type) {
handleIndent();
if (type instanceof ClassType) {
ClassType ctype = (ClassType) type;
final String[] splits = ctype.getPackageName().getPackageName().split("\\.");
for (String split : splits) {
if (split.length() == 0) {
continue;
}
output.append(sootEscape(split));
output.append('.');
}
output.append(sootEscape(ctype.getClassName()));

} else {
// primitivetypes
output.append(type);
}
}

@Override
public void stmt(Stmt currentStmt) {
startStmt(currentStmt);
Expand Down
Loading
Loading