Skip to content

Commit

Permalink
fix: use variable length encoding instead short for offsets (can over…
Browse files Browse the repository at this point in the history
…flow) (#1489)
  • Loading branch information
skylot committed May 22, 2022
1 parent e07332d commit 6448f0e
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 49 deletions.
1 change: 0 additions & 1 deletion jadx-core/src/main/java/jadx/api/JavaClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ public List<Integer> getUsePlacesFor(ICodeInfo codeInfo, JavaNode javaNode) {
// ignore declarations and offset annotations
continue;
}
// ignore declarations
JavaNode annNode = rootDec.getJavaNodeByCodeAnnotation(codeInfo, ann);
if (annNode == null && LOG.isDebugEnabled()) {
LOG.debug("Failed to resolve code annotation, cls: {}, pos: {}, ann: {}", this, entry.getKey(), ann);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import jadx.core.utils.files.FileUtils;
import jadx.gui.utils.codecache.disk.adapters.CodeAnnotationAdapter;

import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.readUVInt;
import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.writeUVInt;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
Expand Down Expand Up @@ -68,8 +70,8 @@ public ICodeInfo readAndBuild(Path metadataFile, String code) {
private void writeLines(DataOutput out, Map<Integer, Integer> lines) throws IOException {
out.writeInt(lines.size());
for (Map.Entry<Integer, Integer> entry : lines.entrySet()) {
out.writeShort(entry.getKey());
out.writeShort(entry.getValue());
writeUVInt(out, entry.getKey());
writeUVInt(out, entry.getValue());
}
}

Expand All @@ -80,8 +82,8 @@ private Map<Integer, Integer> readLines(DataInput in) throws IOException {
}
Map<Integer, Integer> lines = new HashMap<>(size);
for (int i = 0; i < size; i++) {
int key = in.readShort();
int value = in.readShort();
int key = readUVInt(in);
int value = readUVInt(in);
lines.put(key, value);
}
return lines;
Expand All @@ -90,7 +92,7 @@ private Map<Integer, Integer> readLines(DataInput in) throws IOException {
private void writeAnnotations(DataOutputStream out, Map<Integer, ICodeAnnotation> annotations) throws IOException {
out.writeInt(annotations.size());
for (Map.Entry<Integer, ICodeAnnotation> entry : annotations.entrySet()) {
out.writeInt(entry.getKey());
writeUVInt(out, entry.getKey());
codeAnnotationAdapter.write(out, entry.getValue());
}
}
Expand All @@ -102,7 +104,7 @@ private Map<Integer, ICodeAnnotation> readAnnotations(DataInputStream in) throws
}
Map<Integer, ICodeAnnotation> map = new HashMap<>(size);
for (int i = 0; i < size; i++) {
int pos = in.readInt();
int pos = readUVInt(in);
ICodeAnnotation ann = codeAnnotationAdapter.read(in);
if (ann != null) {
map.put(pos, ann);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
public class DiskCodeCache implements ICodeCache {
private static final Logger LOG = LoggerFactory.getLogger(DiskCodeCache.class);

private static final int DATA_FORMAT_VERSION = 8;
private static final int DATA_FORMAT_VERSION = 9;

private final Path srcDir;
private final Path metaDir;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package jadx.gui.utils.codecache.disk.adapters;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.jetbrains.annotations.Nullable;

public class DataAdapterHelper {

public static void writeNullableUTF(DataOutput out, @Nullable String str) throws IOException {
if (str == null) {
out.writeByte(0);
} else {
out.writeByte(1);
out.writeUTF(str);
}
}

public static @Nullable String readNullableUTF(DataInput in) throws IOException {
if (in.readByte() == 0) {
return null;
}
return in.readUTF();
}

/**
* Write unsigned variable length integer (ULEB128 encoding)
*/
public static void writeUVInt(DataOutput out, int val) throws IOException {
if (val < 0) {
throw new IllegalArgumentException("Expect value >= 0, got: " + val);
}
int current = val;
int next = val;
while (true) {
next >>>= 7;
if (next == 0) {
// last byte
out.writeByte(current & 0x7f);
return;
}
out.writeByte((current & 0x7f) | 0x80);
current = next;
}
}

/**
* Read unsigned variable length integer (ULEB128 encoding)
*/
public static int readUVInt(DataInput in) throws IOException {
int result = 0;
int shift = 0;
while (true) {
byte v = in.readByte();
result |= (v & (byte) 0x7f) << shift;
shift += 7;
if ((v & 0x80) != 0x80) {
return result;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public class InsnCodeOffsetAdapter implements DataAdapter<InsnCodeOffset> {

@Override
public void write(DataOutput out, InsnCodeOffset value) throws IOException {
out.writeShort(value.getOffset());
DataAdapterHelper.writeUVInt(out, value.getOffset());
}

@Override
public InsnCodeOffset read(DataInput in) throws IOException {
return new InsnCodeOffset(in.readShort());
return new InsnCodeOffset(DataAdapterHelper.readUVInt(in));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ public void write(DataOutput out, NodeDeclareRef value) throws IOException {
throw new RuntimeException("Null node in NodeDeclareRef");
}
refAdapter.write(out, node);
out.writeShort(value.getDefPos());
DataAdapterHelper.writeUVInt(out, value.getDefPos());
}

@Override
public NodeDeclareRef read(DataInput in) throws IOException {
ICodeNodeRef ref = (ICodeNodeRef) refAdapter.read(in);
int defPos = in.readShort();
int defPos = DataAdapterHelper.readUVInt(in);
NodeDeclareRef nodeDeclareRef = new NodeDeclareRef(ref);
nodeDeclareRef.setDefPos(defPos);
// restore def position if loading metadata without actual decompilation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.MethodNode;

public class VarNodeAdapter extends BaseDataAdapter<VarNode> {
import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.readNullableUTF;
import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.readUVInt;
import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.writeNullableUTF;
import static jadx.gui.utils.codecache.disk.adapters.DataAdapterHelper.writeUVInt;

public class VarNodeAdapter implements DataAdapter<VarNode> {
private final MethodNodeAdapter mthAdapter;

public VarNodeAdapter(MethodNodeAdapter mthAdapter) {
Expand All @@ -18,17 +23,17 @@ public VarNodeAdapter(MethodNodeAdapter mthAdapter) {
@Override
public void write(DataOutput out, VarNode value) throws IOException {
mthAdapter.write(out, value.getMth());
out.writeShort(value.getReg());
out.writeShort(value.getSsa());
writeUVInt(out, value.getReg());
writeUVInt(out, value.getSsa());
ArgTypeAdapter.INSTANCE.write(out, value.getType());
writeNullableUTF(out, value.getName());
}

@Override
public VarNode read(DataInput in) throws IOException {
MethodNode mth = mthAdapter.read(in);
int reg = in.readShort();
int ssa = in.readShort();
int reg = readUVInt(in);
int ssa = readUVInt(in);
ArgType type = ArgTypeAdapter.INSTANCE.read(in);
String name = readNullableUTF(in);
return new VarNode(mth, reg, ssa, type, name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@

import jadx.api.metadata.annotations.VarRef;

public class VarRefAdapter extends BaseDataAdapter<VarRef> {
public class VarRefAdapter implements DataAdapter<VarRef> {

public static final VarRefAdapter INSTANCE = new VarRefAdapter();

@Override
public void write(DataOutput out, VarRef value) throws IOException {
int refPos = value.getRefPos();
if (refPos <= 0) {
throw new RuntimeException("Variable refPos is invalid: " + value);
}
out.writeInt(refPos);
DataAdapterHelper.writeUVInt(out, refPos);
}

@Override
public VarRef read(DataInput in) throws IOException {
return VarRef.fromPos(in.readInt());
int refPos = DataAdapterHelper.readUVInt(in);
return VarRef.fromPos(refPos);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package jadx.gui.utils.codecache.disk.adapters;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class DataAdapterHelperTest {

@Test
void uvInt() throws IOException {
checkUVIntFor(0);
checkUVIntFor(7);
checkUVIntFor(0x7f);
checkUVIntFor(0x80);
checkUVIntFor(0x256);
checkUVIntFor(Byte.MAX_VALUE);
checkUVIntFor(Short.MAX_VALUE);
checkUVIntFor(Integer.MAX_VALUE);
}

private void checkUVIntFor(int val) throws IOException {
assertThat(writeReadUVInt(val)).isEqualTo(val);
}

private int writeReadUVInt(int val) throws IOException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(byteOut);
DataAdapterHelper.writeUVInt(out, val);

DataInput in = new DataInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
return DataAdapterHelper.readUVInt(in);
}
}

0 comments on commit 6448f0e

Please sign in to comment.