Impl of IMethod.is(Wala)Synthetic and IClass.isSynthetic (#359)

* Impl of IMethod isSynthetic and isWalaSynthetic

So far IMethod.isSynthetic referred to WALA-generated helper functions
and there was no equivalent to check whether an IMethod is synthetic in
terms of compiler-generated.

To make naming consistent this patch first renames the isSynthetic to
isWalaSynthetic to clearly indicate that a given IMethod was generated
by WALA. Then, we re-introduce isSynthetic that from now on checks
whether an IMethod is synthetic/compiler-generated (referring to the
synthetic flag in bytecode)

* Implementation of IClass.isSynthetic

Complementary to IMethod.isSynthetic, this method checks whether
an IClass is compiler-generated.

* updated JavaDoc
This commit is contained in:
Erik Derr 2018-10-03 07:28:21 +02:00 committed by Manu Sridharan
parent 751444a656
commit ee13713c4d
24 changed files with 111 additions and 31 deletions

View File

@ -256,7 +256,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall
System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod())); System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod()));
if (node.getMethod().isSynthetic()) { if (node.getMethod().isWalaSynthetic()) {
return; return;
} }

View File

@ -85,6 +85,11 @@ abstract public class AstClass implements IClass, ClassConstants {
return false; return false;
} }
@Override
public boolean isSynthetic() {
return false;
}
@Override @Override
public int getModifiers() { public int getModifiers() {
return modifiers; return modifiers;

View File

@ -91,6 +91,11 @@ abstract public class AstFunctionClass implements IClass, ClassConstants {
return false; return false;
} }
@Override
public boolean isSynthetic() {
return false;
}
@Override @Override
public int getModifiers() { public int getModifiers() {
return ACC_PUBLIC; return ACC_PUBLIC;

View File

@ -267,6 +267,11 @@ public abstract class AstMethod implements IMethod {
return qualifiers.contains(CAstQualifier.NATIVE); return qualifiers.contains(CAstQualifier.NATIVE);
} }
@Override
public boolean isWalaSynthetic() {
return false;
}
@Override @Override
public boolean isSynthetic() { public boolean isSynthetic() {
return false; return false;

View File

@ -141,7 +141,7 @@ public class FactoryBypassInterpreter extends AbstractReflectionInterpreter {
if (node == null) { if (node == null) {
throw new IllegalArgumentException("node is null"); throw new IllegalArgumentException("node is null");
} }
if (node.getMethod().isSynthetic()) { if (node.getMethod().isWalaSynthetic()) {
SyntheticMethod s = (SyntheticMethod) node.getMethod(); SyntheticMethod s = (SyntheticMethod) node.getMethod();
if (s.isFactoryMethod()) { if (s.isFactoryMethod()) {
return getTypesForContext(node.getContext()) != null; return getTypesForContext(node.getContext()) != null;

View File

@ -38,7 +38,7 @@ class FactoryContextSelector implements ContextSelector {
if (callee == null) { if (callee == null) {
throw new IllegalArgumentException("callee is null"); throw new IllegalArgumentException("callee is null");
} }
if (callee.isSynthetic()) { if (callee.isWalaSynthetic()) {
SyntheticMethod s = (SyntheticMethod) callee; SyntheticMethod s = (SyntheticMethod) callee;
if (s.isFactoryMethod()) { if (s.isFactoryMethod()) {
return new CallStringContext(new CallString(site, caller.getMethod())); return new CallStringContext(new CallString(site, caller.getMethod()));

View File

@ -371,6 +371,11 @@ public class ArrayClass implements IClass, Constants {
return false; return false;
} }
@Override
public boolean isSynthetic() {
return false;
}
@Override @Override
public Reader getSource() { public Reader getSource() {
return null; return null;

View File

@ -46,7 +46,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getCallSites(sm.getStatements()); return getCallSites(sm.getStatements());
} else { } else {
@ -62,7 +62,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getFieldsRead(sm.getStatements()); return getFieldsRead(sm.getStatements());
} else { } else {
@ -78,7 +78,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getFieldsWritten(sm.getStatements()); return getFieldsWritten(sm.getStatements());
} else { } else {
@ -95,7 +95,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getArraysWritten(sm.getStatements()); return getArraysWritten(sm.getStatements());
} else { } else {
@ -111,7 +111,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getNewSites(sm.getStatements()); return getNewSites(sm.getStatements());
} else { } else {
@ -123,7 +123,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return hasObjectArrayLoad(sm.getStatements()); return hasObjectArrayLoad(sm.getStatements());
} else { } else {
@ -135,7 +135,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return hasObjectArrayStore(sm.getStatements()); return hasObjectArrayStore(sm.getStatements());
} else { } else {
@ -147,7 +147,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return getCaughtExceptions(sm.getStatements()); return getCaughtExceptions(sm.getStatements());
} else { } else {
@ -166,7 +166,7 @@ public class CodeScanner {
if (m == null) { if (m == null) {
throw new IllegalArgumentException("m is null"); throw new IllegalArgumentException("m is null");
} }
if (m.isSynthetic()) { if (m.isWalaSynthetic()) {
SyntheticMethod sm = (SyntheticMethod) m; SyntheticMethod sm = (SyntheticMethod) m;
return iterateCastTypes(sm.getStatements()); return iterateCastTypes(sm.getStatements());
} else { } else {

View File

@ -54,6 +54,11 @@ public interface IClass extends IClassHierarchyDweller {
*/ */
boolean isPrivate(); boolean isPrivate();
/**
* @return true iff this class is synthetic, i.e., compiler-generated
*/
boolean isSynthetic();
/** /**
* Return the integer that encodes the class's modifiers, as defined by the JVM specification * Return the integer that encodes the class's modifiers, as defined by the JVM specification
* *

View File

@ -43,7 +43,14 @@ public interface IMethod extends IMember, ContextItem {
boolean isNative(); boolean isNative();
/** /**
* Did someone synthesize this method? (As opposed to reading it from a class file) * Is the implementation of this method a model generated by WALA?
* For compiler-generated synthetic methods, refer to {@link #isSynthetic()}
*/
boolean isWalaSynthetic();
/**
* Is this method synthetic, i.e., compiler-generated (this refers to the
* synthetic flag in java/dex bytecode)
*/ */
boolean isSynthetic(); boolean isSynthetic();

View File

@ -65,6 +65,15 @@ public abstract class JVMClass<T extends IClassLoader> extends BytecodeClass<T>
return result; return result;
} }
/*
* @see com.ibm.wala.classLoader.IClass#isSynthetic()
*/
@Override
public boolean isSynthetic() {
boolean result = ((modifiers & Constants.ACC_SYNTHETIC) != 0);
return result;
}
/** /**
* @see com.ibm.wala.classLoader.IClass#getClassInitializer() * @see com.ibm.wala.classLoader.IClass#getClassInitializer()
*/ */

View File

@ -441,7 +441,10 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
} }
@Override @Override
public boolean isSynthetic() { public boolean isSynthetic() { return ((getModifiers() & Constants.ACC_SYNTHETIC) != 0); }
@Override
public boolean isWalaSynthetic() {
return false; return false;
} }

View File

@ -95,6 +95,16 @@ public abstract class SyntheticClass implements IClass {
return false; return false;
} }
/*
* These classes are generated by WALA, not by any
* compiler, therefore it always returns false
* @see com.ibm.wala.classLoader.IClass#isSynthetic()
*/
@Override
public boolean isSynthetic() {
return false;
}
/* /*
* @see com.ibm.wala.classLoader.IClass#getReference() * @see com.ibm.wala.classLoader.IClass#getReference()
*/ */
@ -123,7 +133,7 @@ public abstract class SyntheticClass implements IClass {
public boolean isArrayClass() { public boolean isArrayClass() {
return false; return false;
} }
@Override @Override
public IClassHierarchy getClassHierarchy() { public IClassHierarchy getClassHierarchy() {
return cha; return cha;

View File

@ -153,12 +153,20 @@ public class SyntheticMethod implements IMethod {
return false; return false;
} }
/**
* @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic()
*/
@Override
public boolean isWalaSynthetic() {
return true;
}
/** /**
* @see com.ibm.wala.classLoader.IMethod#isSynthetic() * @see com.ibm.wala.classLoader.IMethod#isSynthetic()
*/ */
@Override @Override
public boolean isSynthetic() { public boolean isSynthetic() {
return true; return false;
} }
/** /**

View File

@ -102,7 +102,7 @@ public class SimpleMemoryAccessMap implements MemoryAccessMap {
private void populate(CGNode n) { private void populate(CGNode n) {
// we analyze bytecodes to avoid the cost of IR construction, except // we analyze bytecodes to avoid the cost of IR construction, except
// for synthetic methods, where we must use the synthetic IR // for synthetic methods, where we must use the synthetic IR
if (ALWAYS_BUILD_IR || n.getMethod().isSynthetic()) { if (ALWAYS_BUILD_IR || n.getMethod().isWalaSynthetic()) {
if (DEBUG) { if (DEBUG) {
System.err.println("synthetic method"); System.err.println("synthetic method");
} }

View File

@ -184,7 +184,7 @@ public abstract class BasicCallGraph<T> extends AbstractNumberedGraph<CGNode> im
protected NodeImpl(IMethod method, Context C) { protected NodeImpl(IMethod method, Context C) {
this.method = method; this.method = method;
this.context = C; this.context = C;
if (method != null && !method.isSynthetic() && method.isAbstract()) { if (method != null && !method.isWalaSynthetic() && method.isAbstract()) {
assert !method.isAbstract() : "Abstract method " + method; assert !method.isAbstract() : "Abstract method " + method;
} }
assert C != null; assert C != null;

View File

@ -297,7 +297,7 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
@Override @Override
public IR getIR() { public IR getIR() {
if (getMethod().isSynthetic()) { if (getMethod().isWalaSynthetic()) {
// disable local cache in this case, as context interpreters // disable local cache in this case, as context interpreters
// do weird things like mutate IRs // do weird things like mutate IRs
return getCallGraph().getInterpreter(this).getIR(this); return getCallGraph().getInterpreter(this).getIR(this);
@ -312,7 +312,7 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
@Override @Override
public DefUse getDU() { public DefUse getDU() {
if (getMethod().isSynthetic()) { if (getMethod().isWalaSynthetic()) {
// disable local cache in this case, as context interpreters // disable local cache in this case, as context interpreters
// do weird things like mutate IRs // do weird things like mutate IRs
return getCallGraph().getInterpreter(this).getDU(this); return getCallGraph().getInterpreter(this).getDU(this);

View File

@ -40,7 +40,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
if (method == null) { if (method == null) {
throw new IllegalArgumentException("method cannot be null"); throw new IllegalArgumentException("method cannot be null");
} }
if (method.isSynthetic()) { if (method.isWalaSynthetic()) {
return syntheticFactory.makeCFG((SyntheticMethod) method); return syntheticFactory.makeCFG((SyntheticMethod) method);
} else if (method instanceof IBytecodeMethod) { } else if (method instanceof IBytecodeMethod) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -61,7 +61,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
if (method == null) { if (method == null) {
throw new IllegalArgumentException("method cannot be null"); throw new IllegalArgumentException("method cannot be null");
} }
if (method.isSynthetic()) { if (method.isWalaSynthetic()) {
return syntheticFactory.makeIR((SyntheticMethod) method, c, options); return syntheticFactory.makeIR((SyntheticMethod) method, c, options);
} else if (method instanceof IBytecodeMethod) { } else if (method instanceof IBytecodeMethod) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -81,7 +81,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
if (method == null) { if (method == null) {
throw new IllegalArgumentException("null method"); throw new IllegalArgumentException("null method");
} }
if (method.isSynthetic()) { if (method.isWalaSynthetic()) {
return syntheticFactory.contextIsIrrelevant((SyntheticMethod) method); return syntheticFactory.contextIsIrrelevant((SyntheticMethod) method);
} else if (method instanceof ShrikeCTMethod) { } else if (method instanceof ShrikeCTMethod) {
// we know ShrikeFactory contextIsIrrelevant // we know ShrikeFactory contextIsIrrelevant

View File

@ -63,9 +63,9 @@ public class JVMLDalvikComparisonTest extends DalvikCallGraphTestBase {
private static Set<Pair<CGNode,CGNode>> edgeDiff(CallGraph from, CallGraph to, boolean userOnly) { private static Set<Pair<CGNode,CGNode>> edgeDiff(CallGraph from, CallGraph to, boolean userOnly) {
Set<Pair<CGNode,CGNode>> result = HashSetFactory.make(); Set<Pair<CGNode,CGNode>> result = HashSetFactory.make();
for(CGNode f : from) { for(CGNode f : from) {
if (! f.getMethod().isSynthetic()) { if (! f.getMethod().isWalaSynthetic()) {
outer: for(CGNode t : from) { outer: for(CGNode t : from) {
if (!t.getMethod().isSynthetic() && if (!t.getMethod().isWalaSynthetic() &&
from.hasEdge(f, t) && from.hasEdge(f, t) &&
(!userOnly || (!userOnly ||
!t.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Primordial))) !t.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Primordial)))

View File

@ -51,6 +51,7 @@ import static org.jf.dexlib2.AccessFlags.ABSTRACT;
import static org.jf.dexlib2.AccessFlags.INTERFACE; import static org.jf.dexlib2.AccessFlags.INTERFACE;
import static org.jf.dexlib2.AccessFlags.PRIVATE; import static org.jf.dexlib2.AccessFlags.PRIVATE;
import static org.jf.dexlib2.AccessFlags.PUBLIC; import static org.jf.dexlib2.AccessFlags.PUBLIC;
import static org.jf.dexlib2.AccessFlags.SYNTHETIC;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -229,6 +230,13 @@ public class DexIClass extends BytecodeClass<IClassLoader> {
return (modifiers & ABSTRACT.getValue()) != 0; return (modifiers & ABSTRACT.getValue()) != 0;
} }
/*
* @see com.ibm.wala.classLoader.IClass#isAbstract()
*/
@Override
public boolean isSynthetic() {
return (modifiers & SYNTHETIC.getValue()) != 0;
}
/* /*
* (non-Javadoc) * (non-Javadoc)

View File

@ -59,6 +59,7 @@ import static org.jf.dexlib2.AccessFlags.PROTECTED;
import static org.jf.dexlib2.AccessFlags.PUBLIC; import static org.jf.dexlib2.AccessFlags.PUBLIC;
import static org.jf.dexlib2.AccessFlags.STATIC; import static org.jf.dexlib2.AccessFlags.STATIC;
import static org.jf.dexlib2.AccessFlags.VOLATILE; import static org.jf.dexlib2.AccessFlags.VOLATILE;
import static org.jf.dexlib2.AccessFlags.SYNTHETIC;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -508,13 +509,20 @@ public class DexIMethod implements IBytecodeMethod<Instruction> {
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see com.ibm.wala.classLoader.IMethod#isSynthetic() * @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic()
*/ */
@Override @Override
public boolean isSynthetic() { public boolean isWalaSynthetic() {
return false; return false;
} }
/*
* (non-Javadoc)
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
*/
@Override
public boolean isSynthetic() { return (eMethod.getAccessFlags() & SYNTHETIC.getValue()) != 0; }
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see com.ibm.wala.classLoader.IMember#isStatic() * @see com.ibm.wala.classLoader.IMember#isStatic()

View File

@ -436,7 +436,7 @@ implements IFlowFunctionMap<BasicBlockInContext<E>> {
final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction(); final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
// String signature = dest.getMethod().getSignature(); // String signature = dest.getMethod().getSignature();
// if ( dest.getMethod().isSynthetic() ) { // if ( dest.getMethod().isWalaSynthetic() ) {
// System.out.println("Synthetic: "+signature); // System.out.println("Synthetic: "+signature);
// } else { // } else {
// System.err.println(signature); // System.err.println(signature);
@ -448,7 +448,7 @@ implements IFlowFunctionMap<BasicBlockInContext<E>> {
// System.out.println("Call to system: "+signature); // System.out.println("Call to system: "+signature);
// } // }
// if (! dest.getMethod().isSynthetic() // if (! dest.getMethod().isWalaSynthetic()
// && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) { // && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) {
// //
// MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " + dest.getMethod().getReference()); // MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " + dest.getMethod().getReference());

View File

@ -195,7 +195,7 @@ public class CGAnalysisContext<E extends ISSABasicBlock> {
Warnings.clear(); Warnings.clear();
pa = cgb.getPointerAnalysis(); pa = cgb.getPointerAnalysis();
partialGraph = GraphSlicer.prune(cg, node -> LoaderUtils.fromLoader(node, ClassLoaderReference.Application) || node.getMethod().isSynthetic()); partialGraph = GraphSlicer.prune(cg, node -> LoaderUtils.fromLoader(node, ClassLoaderReference.Application) || node.getMethod().isWalaSynthetic());
if (options.includeLibrary()) { if (options.includeLibrary()) {
graph = (ISupergraph) ICFGSupergraph.make(cg); graph = (ISupergraph) ICFGSupergraph.make(cg);
} else { } else {
@ -271,7 +271,7 @@ public class CGAnalysisContext<E extends ISSABasicBlock> {
} }
} }
for (CGNode node : Iterator2Iterable.make(cg.iterator())) { for (CGNode node : Iterator2Iterable.make(cg.iterator())) {
if (node.getMethod().isSynthetic()) { if (node.getMethod().isWalaSynthetic()) {
SSACFG ssaCFG = node.getIR().getControlFlowGraph(); SSACFG ssaCFG = node.getIR().getControlFlowGraph();
int totalBlocks = ssaCFG.getNumberOfNodes(); int totalBlocks = ssaCFG.getNumberOfNodes();
for (int i = 0; i < totalBlocks; i++) { for (int i = 0; i < totalBlocks; i++) {

View File

@ -464,6 +464,8 @@ public interface Constants {
public static final short ACC_STRICT = 0x800; public static final short ACC_STRICT = 0x800;
public static final short ACC_SYNTHETIC = 0x1000;
public static final byte CONSTANT_Utf8 = 1; public static final byte CONSTANT_Utf8 = 1;
public static final byte CONSTANT_Integer = 3; public static final byte CONSTANT_Integer = 3;