Skip to content

Commit c9d650d

Browse files
committed
fix: unload attributes map if empty (#2433)
1 parent ce60aa8 commit c9d650d

File tree

6 files changed

+41
-24
lines changed

6 files changed

+41
-24
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jadx-output/
3232
*.jadx
3333

3434
*.class
35+
*.jar
3536
*.dump
3637
*.log
3738
*.cfg

jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
public abstract class AttrNode implements IAttributeNode {
1414

15-
private static final AttributeStorage EMPTY_ATTR_STORAGE = new EmptyAttrStorage();
15+
private static final AttributeStorage EMPTY_ATTR_STORAGE = EmptyAttrStorage.INSTANCE;
1616

1717
private AttributeStorage storage = EMPTY_ATTR_STORAGE;
1818

@@ -35,6 +35,9 @@ public void addAttr(IJadxAttribute attr) {
3535

3636
@Override
3737
public void addAttrs(List<IJadxAttribute> list) {
38+
if (list.isEmpty()) {
39+
return;
40+
}
3841
initStorage().add(list);
3942
}
4043

jadx-core/src/main/java/jadx/core/dex/attributes/AttributeStorage.java

+20-15
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,34 @@
1818
import jadx.core.utils.exceptions.JadxRuntimeException;
1919

2020
/**
21-
* Storage for different attribute types:
22-
* 1. flags - boolean attribute (set or not)
23-
* 2. attribute - class instance associated with attribute type.
21+
* Storage for different attribute types:<br>
22+
* 1. Flags - boolean attribute (set or not)<br>
23+
* 2. Attributes - class instance ({@link IJadxAttribute}) associated with an attribute type
24+
* ({@link IJadxAttrType})<br>
2425
*/
2526
public class AttributeStorage {
2627

28+
public static AttributeStorage fromList(List<IJadxAttribute> list) {
29+
AttributeStorage storage = new AttributeStorage();
30+
storage.add(list);
31+
return storage;
32+
}
33+
2734
static {
2835
int flagsCount = AFlag.values().length;
2936
if (flagsCount >= 64) {
3037
throw new JadxRuntimeException("Try to reduce flags count to 64 for use one long in EnumSet, now " + flagsCount);
3138
}
3239
}
3340

41+
private static final Map<IJadxAttrType<?>, IJadxAttribute> EMPTY_ATTRIBUTES = Collections.emptyMap();
42+
3443
private final Set<AFlag> flags;
3544
private Map<IJadxAttrType<?>, IJadxAttribute> attributes;
3645

3746
public AttributeStorage() {
3847
flags = EnumSet.noneOf(AFlag.class);
39-
attributes = Collections.emptyMap();
40-
}
41-
42-
public AttributeStorage(List<IJadxAttribute> attributesList) {
43-
this();
44-
add(attributesList);
48+
attributes = EMPTY_ATTRIBUTES;
4549
}
4650

4751
public void add(AFlag flag) {
@@ -125,21 +129,22 @@ public void remove(IJadxAttribute attr) {
125129
}
126130

127131
private void writeAttributes(Consumer<Map<IJadxAttrType<?>, IJadxAttribute>> mapConsumer) {
128-
if (attributes.isEmpty()) {
129-
attributes = new IdentityHashMap<>(5);
130-
}
131132
synchronized (this) {
133+
if (attributes == EMPTY_ATTRIBUTES) {
134+
attributes = new IdentityHashMap<>(2); // only 1 or 2 attributes added in most cases
135+
}
132136
mapConsumer.accept(attributes);
137+
if (attributes.isEmpty()) {
138+
attributes = EMPTY_ATTRIBUTES;
139+
}
133140
}
134141
}
135142

136143
public void unloadAttributes() {
137144
if (attributes.isEmpty()) {
138145
return;
139146
}
140-
synchronized (this) {
141-
attributes.entrySet().removeIf(entry -> !entry.getValue().keepLoaded());
142-
}
147+
writeAttributes(map -> map.entrySet().removeIf(entry -> !entry.getValue().keepLoaded()));
143148
}
144149

145150
public List<String> getAttributeStrings() {

jadx-core/src/main/java/jadx/core/dex/attributes/EmptyAttrStorage.java

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99

1010
public final class EmptyAttrStorage extends AttributeStorage {
1111

12+
public static final AttributeStorage INSTANCE = new EmptyAttrStorage();
13+
14+
private EmptyAttrStorage() {
15+
// singleton
16+
}
17+
1218
@Override
1319
public boolean contains(AFlag flag) {
1420
return false;

jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,14 @@ private void writeClass(SmaliWriter smali, ClassNode cls) {
185185
smali.startLine(String.format("###### Class %s is created by jadx", cls.getFullName()));
186186
return;
187187
}
188-
AttributeStorage attributes = new AttributeStorage();
189-
attributes.add(clsData.getAttributes());
190-
188+
AttributeStorage clsAttributes = AttributeStorage.fromList(clsData.getAttributes());
191189
smali.startLine("Class: " + clsData.getType())
192190
.startLine("AccessFlags: " + AccessFlags.format(clsData.getAccessFlags(), AccessFlagsScope.CLASS))
193191
.startLine("SuperType: " + clsData.getSuperType())
194192
.startLine("Interfaces: " + clsData.getInterfacesTypes())
195-
.startLine("SourceFile: " + attributes.get(JadxAttrType.SOURCE_FILE));
193+
.startLine("SourceFile: " + clsAttributes.get(JadxAttrType.SOURCE_FILE));
196194

197-
AnnotationsAttr annotationsAttr = attributes.get(JadxAttrType.ANNOTATION_LIST);
195+
AnnotationsAttr annotationsAttr = clsAttributes.get(JadxAttrType.ANNOTATION_LIST);
198196
if (annotationsAttr != null) {
199197
Collection<IAnnotation> annos = annotationsAttr.getList();
200198
if (!annos.isEmpty()) {
@@ -451,7 +449,8 @@ private void writeMethodDef(SmaliWriter smali, IMethodData mth, LineInfo lineInf
451449
smali.add(')');
452450
smali.add(methodRef.getReturnType());
453451

454-
AnnotationsAttr annotationsAttr = new AttributeStorage(mth.getAttributes()).get(JadxAttrType.ANNOTATION_LIST);
452+
AttributeStorage mthAttributes = AttributeStorage.fromList(mth.getAttributes());
453+
AnnotationsAttr annotationsAttr = mthAttributes.get(JadxAttrType.ANNOTATION_LIST);
455454
if (annotationsAttr != null && !annotationsAttr.isEmpty()) {
456455
smali.incIndent();
457456
writeAnnotations(smali, annotationsAttr.getList());
@@ -1074,7 +1073,7 @@ private static RawField make(IFieldData f) {
10741073
field.accessFlag = AccessFlags.format(f.getAccessFlags(), FIELD);
10751074
field.name = f.getName();
10761075
field.type = f.getType();
1077-
field.attributes = new AttributeStorage(f.getAttributes());
1076+
field.attributes = AttributeStorage.fromList(f.getAttributes());
10781077
return field;
10791078
}
10801079
}

jadx-plugins/jadx-input-api/src/main/java/jadx/api/plugins/input/data/attributes/IJadxAttribute.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package jadx.api.plugins.input.data.attributes;
22

3+
/**
4+
* Jadx attribute: custom data container, can be added to most jadx nodes.
5+
*/
36
public interface IJadxAttribute {
47

58
IJadxAttrType<? extends IJadxAttribute> getAttrType();
69

710
/**
8-
* Mark type to skip unloading on node unload
11+
* Mark type to skip unloading on node unload event
912
*/
1013
default boolean keepLoaded() {
1114
return false;

0 commit comments

Comments
 (0)