fix: resolve JavaNode caching issues (#1775)
This commit is contained in:
@@ -12,7 +12,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -93,10 +92,6 @@ public final class JadxDecompiler implements Closeable {
|
||||
private BinaryXMLParser binaryXmlParser;
|
||||
private ProtoXMLParser protoXmlParser;
|
||||
|
||||
private final Map<ClassNode, JavaClass> classesMap = new ConcurrentHashMap<>();
|
||||
private final Map<MethodNode, JavaMethod> methodsMap = new ConcurrentHashMap<>();
|
||||
private final Map<FieldNode, JavaField> fieldsMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final IDecompileScheduler decompileScheduler = new DecompilerScheduler();
|
||||
|
||||
private final List<ILoadResult> customLoads = new ArrayList<>();
|
||||
@@ -155,10 +150,6 @@ public final class JadxDecompiler implements Closeable {
|
||||
resources = null;
|
||||
binaryXmlParser = null;
|
||||
protoXmlParser = null;
|
||||
|
||||
classesMap.clear();
|
||||
methodsMap.clear();
|
||||
fieldsMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -471,33 +462,36 @@ public final class JadxDecompiler implements Closeable {
|
||||
* Get JavaClass by ClassNode without loading and decompilation
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
JavaClass convertClassNode(ClassNode cls) {
|
||||
return classesMap.compute(cls, (node, prevJavaCls) -> {
|
||||
if (prevJavaCls != null && prevJavaCls.getClassNode() == cls) {
|
||||
// keep previous variable
|
||||
return prevJavaCls;
|
||||
}
|
||||
if (cls.isInner()) {
|
||||
return new JavaClass(cls, convertClassNode(cls.getParentClass()));
|
||||
}
|
||||
return new JavaClass(cls, this);
|
||||
});
|
||||
synchronized JavaClass convertClassNode(ClassNode cls) {
|
||||
JavaClass javaClass = cls.getJavaNode();
|
||||
if (javaClass == null) {
|
||||
javaClass = cls.isInner()
|
||||
? new JavaClass(cls, convertClassNode(cls.getParentClass()))
|
||||
: new JavaClass(cls, this);
|
||||
cls.setJavaNode(javaClass);
|
||||
}
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
JavaField convertFieldNode(FieldNode field) {
|
||||
return fieldsMap.computeIfAbsent(field, fldNode -> {
|
||||
JavaClass parentCls = convertClassNode(fldNode.getParentClass());
|
||||
return new JavaField(parentCls, fldNode);
|
||||
});
|
||||
synchronized JavaField convertFieldNode(FieldNode fld) {
|
||||
JavaField javaField = fld.getJavaNode();
|
||||
if (javaField == null) {
|
||||
JavaClass parentCls = convertClassNode(fld.getParentClass());
|
||||
javaField = new JavaField(parentCls, fld);
|
||||
fld.setJavaNode(javaField);
|
||||
}
|
||||
return javaField;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
JavaMethod convertMethodNode(MethodNode method) {
|
||||
return methodsMap.computeIfAbsent(method, mthNode -> {
|
||||
ClassNode parentCls = mthNode.getParentClass();
|
||||
return new JavaMethod(convertClassNode(parentCls), mthNode);
|
||||
});
|
||||
synchronized JavaMethod convertMethodNode(MethodNode mth) {
|
||||
JavaMethod javaMethod = mth.getJavaNode();
|
||||
if (javaMethod == null) {
|
||||
javaMethod = new JavaMethod(convertClassNode(mth.getParentClass()), mth);
|
||||
mth.setJavaNode(javaMethod);
|
||||
}
|
||||
return javaMethod;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -574,14 +568,9 @@ public final class JadxDecompiler implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JavaVariable resolveVarNode(VarNode varNode) {
|
||||
MethodNode mthNode = varNode.getMth();
|
||||
JavaMethod mth = convertMethodNode(mthNode);
|
||||
if (mth == null) {
|
||||
return null;
|
||||
}
|
||||
return new JavaVariable(mth, varNode);
|
||||
JavaMethod javaNode = convertMethodNode(varNode.getMth());
|
||||
return new JavaVariable(javaNode, varNode);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -21,6 +21,7 @@ import jadx.api.ICodeCache;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.impl.SimpleCodeInfo;
|
||||
import jadx.api.plugins.input.data.IClassData;
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
@@ -100,6 +101,8 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
// cache maps
|
||||
private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();
|
||||
|
||||
private JavaClass javaNode;
|
||||
|
||||
public ClassNode(RootNode root, IClassData cls) {
|
||||
this.root = root;
|
||||
this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType()));
|
||||
@@ -835,6 +838,14 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
return clsData == null ? "synthetic" : clsData.getInputFileName();
|
||||
}
|
||||
|
||||
public JavaClass getJavaNode() {
|
||||
return javaNode;
|
||||
}
|
||||
|
||||
public void setJavaNode(JavaClass javaNode) {
|
||||
this.javaNode = javaNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnType getAnnType() {
|
||||
return AnnType.CLASS;
|
||||
|
||||
@@ -3,6 +3,7 @@ package jadx.core.dex.nodes;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.JavaField;
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.core.dex.attributes.nodes.NotificationAttrNode;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
@@ -21,6 +22,8 @@ public class FieldNode extends NotificationAttrNode implements ICodeNode {
|
||||
|
||||
private List<MethodNode> useIn = Collections.emptyList();
|
||||
|
||||
private JavaField javaNode;
|
||||
|
||||
public static FieldNode build(ClassNode cls, IFieldData fieldData) {
|
||||
FieldInfo fieldInfo = FieldInfo.fromRef(cls.root(), fieldData);
|
||||
FieldNode fieldNode = new FieldNode(cls, fieldInfo, fieldData.getAccessFlags());
|
||||
@@ -112,6 +115,14 @@ public class FieldNode extends NotificationAttrNode implements ICodeNode {
|
||||
return parentClass.root();
|
||||
}
|
||||
|
||||
public JavaField getJavaNode() {
|
||||
return javaNode;
|
||||
}
|
||||
|
||||
public void setJavaNode(JavaField javaNode) {
|
||||
this.javaNode = javaNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnType getAnnType() {
|
||||
return AnnType.FIELD;
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JavaMethod;
|
||||
import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.api.plugins.input.data.IDebugInfo;
|
||||
import jadx.api.plugins.input.data.IMethodData;
|
||||
@@ -71,6 +72,8 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
|
||||
private List<MethodNode> useIn = Collections.emptyList();
|
||||
|
||||
private JavaMethod javaNode;
|
||||
|
||||
public static MethodNode build(ClassNode classNode, IMethodData methodData) {
|
||||
MethodNode methodNode = new MethodNode(classNode, methodData);
|
||||
methodNode.addAttrs(methodData.getAttributes());
|
||||
@@ -610,6 +613,14 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
this.useIn = useIn;
|
||||
}
|
||||
|
||||
public JavaMethod getJavaNode() {
|
||||
return javaNode;
|
||||
}
|
||||
|
||||
public void setJavaNode(JavaMethod javaNode) {
|
||||
this.javaNode = javaNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnType getAnnType() {
|
||||
return AnnType.METHOD;
|
||||
|
||||
@@ -141,6 +141,10 @@ public final class FridaAction extends JNodeAction {
|
||||
}
|
||||
return null;
|
||||
});
|
||||
int argsCount = javaMethod.getMethodNode().getMethodInfo().getArgsCount();
|
||||
if (argNames.size() != argsCount) {
|
||||
LOG.warn("Incorrect args count, expected: {}, got: {}", argsCount, argNames.size());
|
||||
}
|
||||
return argNames;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user