fix: unload attributes map if empty (#2433)

This commit is contained in:
Skylot
2025-03-06 19:36:46 +00:00
parent ce60aa8635
commit c9d650d186
6 changed files with 41 additions and 24 deletions
+1
View File
@@ -32,6 +32,7 @@ jadx-output/
*.jadx
*.class
*.jar
*.dump
*.log
*.cfg
@@ -12,7 +12,7 @@ import jadx.core.utils.Utils;
public abstract class AttrNode implements IAttributeNode {
private static final AttributeStorage EMPTY_ATTR_STORAGE = new EmptyAttrStorage();
private static final AttributeStorage EMPTY_ATTR_STORAGE = EmptyAttrStorage.INSTANCE;
private AttributeStorage storage = EMPTY_ATTR_STORAGE;
@@ -35,6 +35,9 @@ public abstract class AttrNode implements IAttributeNode {
@Override
public void addAttrs(List<IJadxAttribute> list) {
if (list.isEmpty()) {
return;
}
initStorage().add(list);
}
@@ -18,12 +18,19 @@ import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
/**
* Storage for different attribute types:
* 1. flags - boolean attribute (set or not)
* 2. attribute - class instance associated with attribute type.
* Storage for different attribute types:<br>
* 1. Flags - boolean attribute (set or not)<br>
* 2. Attributes - class instance ({@link IJadxAttribute}) associated with an attribute type
* ({@link IJadxAttrType})<br>
*/
public class AttributeStorage {
public static AttributeStorage fromList(List<IJadxAttribute> list) {
AttributeStorage storage = new AttributeStorage();
storage.add(list);
return storage;
}
static {
int flagsCount = AFlag.values().length;
if (flagsCount >= 64) {
@@ -31,17 +38,14 @@ public class AttributeStorage {
}
}
private static final Map<IJadxAttrType<?>, IJadxAttribute> EMPTY_ATTRIBUTES = Collections.emptyMap();
private final Set<AFlag> flags;
private Map<IJadxAttrType<?>, IJadxAttribute> attributes;
public AttributeStorage() {
flags = EnumSet.noneOf(AFlag.class);
attributes = Collections.emptyMap();
}
public AttributeStorage(List<IJadxAttribute> attributesList) {
this();
add(attributesList);
attributes = EMPTY_ATTRIBUTES;
}
public void add(AFlag flag) {
@@ -125,11 +129,14 @@ public class AttributeStorage {
}
private void writeAttributes(Consumer<Map<IJadxAttrType<?>, IJadxAttribute>> mapConsumer) {
if (attributes.isEmpty()) {
attributes = new IdentityHashMap<>(5);
}
synchronized (this) {
if (attributes == EMPTY_ATTRIBUTES) {
attributes = new IdentityHashMap<>(2); // only 1 or 2 attributes added in most cases
}
mapConsumer.accept(attributes);
if (attributes.isEmpty()) {
attributes = EMPTY_ATTRIBUTES;
}
}
}
@@ -137,9 +144,7 @@ public class AttributeStorage {
if (attributes.isEmpty()) {
return;
}
synchronized (this) {
attributes.entrySet().removeIf(entry -> !entry.getValue().keepLoaded());
}
writeAttributes(map -> map.entrySet().removeIf(entry -> !entry.getValue().keepLoaded()));
}
public List<String> getAttributeStrings() {
@@ -9,6 +9,12 @@ import jadx.api.plugins.input.data.attributes.IJadxAttribute;
public final class EmptyAttrStorage extends AttributeStorage {
public static final AttributeStorage INSTANCE = new EmptyAttrStorage();
private EmptyAttrStorage() {
// singleton
}
@Override
public boolean contains(AFlag flag) {
return false;
@@ -185,16 +185,14 @@ public class Smali {
smali.startLine(String.format("###### Class %s is created by jadx", cls.getFullName()));
return;
}
AttributeStorage attributes = new AttributeStorage();
attributes.add(clsData.getAttributes());
AttributeStorage clsAttributes = AttributeStorage.fromList(clsData.getAttributes());
smali.startLine("Class: " + clsData.getType())
.startLine("AccessFlags: " + AccessFlags.format(clsData.getAccessFlags(), AccessFlagsScope.CLASS))
.startLine("SuperType: " + clsData.getSuperType())
.startLine("Interfaces: " + clsData.getInterfacesTypes())
.startLine("SourceFile: " + attributes.get(JadxAttrType.SOURCE_FILE));
.startLine("SourceFile: " + clsAttributes.get(JadxAttrType.SOURCE_FILE));
AnnotationsAttr annotationsAttr = attributes.get(JadxAttrType.ANNOTATION_LIST);
AnnotationsAttr annotationsAttr = clsAttributes.get(JadxAttrType.ANNOTATION_LIST);
if (annotationsAttr != null) {
Collection<IAnnotation> annos = annotationsAttr.getList();
if (!annos.isEmpty()) {
@@ -451,7 +449,8 @@ public class Smali {
smali.add(')');
smali.add(methodRef.getReturnType());
AnnotationsAttr annotationsAttr = new AttributeStorage(mth.getAttributes()).get(JadxAttrType.ANNOTATION_LIST);
AttributeStorage mthAttributes = AttributeStorage.fromList(mth.getAttributes());
AnnotationsAttr annotationsAttr = mthAttributes.get(JadxAttrType.ANNOTATION_LIST);
if (annotationsAttr != null && !annotationsAttr.isEmpty()) {
smali.incIndent();
writeAnnotations(smali, annotationsAttr.getList());
@@ -1074,7 +1073,7 @@ public class Smali {
field.accessFlag = AccessFlags.format(f.getAccessFlags(), FIELD);
field.name = f.getName();
field.type = f.getType();
field.attributes = new AttributeStorage(f.getAttributes());
field.attributes = AttributeStorage.fromList(f.getAttributes());
return field;
}
}
@@ -1,11 +1,14 @@
package jadx.api.plugins.input.data.attributes;
/**
* Jadx attribute: custom data container, can be added to most jadx nodes.
*/
public interface IJadxAttribute {
IJadxAttrType<? extends IJadxAttribute> getAttrType();
/**
* Mark type to skip unloading on node unload
* Mark type to skip unloading on node unload event
*/
default boolean keepLoaded() {
return false;