fix: correct detection of exits in synchronized block (#942)

This commit is contained in:
Skylot
2020-08-09 15:00:50 +01:00
parent 593a32a689
commit d6ad21f6f9
4 changed files with 148 additions and 8 deletions
@@ -1,6 +1,6 @@
package jadx.core.dex.regions;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import jadx.core.dex.nodes.IContainer;
@@ -10,7 +10,7 @@ import jadx.core.dex.nodes.InsnNode;
public final class SynchronizedRegion extends AbstractRegion {
private final InsnNode enterInsn;
private final List<InsnNode> exitInsns = new LinkedList<>();
private final List<InsnNode> exitInsns = new ArrayList<>();
private final Region region;
public SynchronizedRegion(IRegion parent, InsnNode insn) {
@@ -6,7 +6,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -538,17 +537,22 @@ public class BlockUtils {
}
public static List<BlockNode> buildSimplePath(BlockNode block) {
List<BlockNode> list = new LinkedList<>();
BlockNode currentBlock = block;
if (block == null) {
return Collections.emptyList();
}
List<BlockNode> list = new ArrayList<>();
if (block.getCleanSuccessors().size() >= 2) {
return Collections.emptyList();
}
list.add(block);
BlockNode currentBlock = getNextBlock(block);
while (currentBlock != null
&& currentBlock.getCleanSuccessors().size() < 2
&& currentBlock.getPredecessors().size() == 1) {
list.add(currentBlock);
currentBlock = getNextBlock(currentBlock);
}
if (list.isEmpty()) {
return Collections.emptyList();
}
return list;
}
@@ -0,0 +1,31 @@
package jadx.tests.integration.synchronize;
import org.junit.jupiter.api.Test;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestSynchronized4 extends SmaliTest {
// @formatter:off
/*
public boolean test(int i) {
synchronized (this.obj) {
if (isZero(i)) {
return call(obj, i);
}
System.out.println();
return getField() == null;
}
}
*/
// @formatter:on
@Test
public void test() {
assertThat(getClassNodeFromSmali())
.code()
.containsOne("synchronized (this.obj) {");
}
}
@@ -0,0 +1,105 @@
.class public Lsynchronize/TestSynchronized4;
.super Ljava/lang/Object;
.field private final obj:Ljava/lang/Object;
.method public constructor <init>()V
.registers 2
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
new-instance v0, Ljava/lang/Object;
invoke-direct {v0}, Ljava/lang/Object;-><init>()V
iput-object v0, p0, Lsynchronize/TestSynchronized4;->obj:Ljava/lang/Object;
return-void
.end method
.method public test(I)Z
.registers 4
iget-object v1, p0, Lsynchronize/TestSynchronized4;->obj:Ljava/lang/Object;
monitor-enter v1
:try_start_3
invoke-direct {p0, p1}, Lsynchronize/TestSynchronized4;->isZero(I)Z
move-result v0
if-eqz v0, :cond_11
iget-object v0, p0, Lsynchronize/TestSynchronized4;->obj:Ljava/lang/Object;
invoke-direct {p0, v0, p1}, Lsynchronize/TestSynchronized4;->call(Ljava/lang/Object;I)Z
move-result v0
monitor-exit v1
:goto_10
return v0
:cond_11
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual {v0}, Ljava/io/PrintStream;->println()V
invoke-direct {p0}, Lsynchronize/TestSynchronized4;->getField()Ljava/lang/Object;
move-result-object v0
if-nez v0, :cond_22
const/4 v0, 0x1
:goto_1d
monitor-exit v1
return v0
:catchall_1f
move-exception v0
monitor-exit v1
:try_end_21
.catchall {:try_start_3 .. :try_end_21} :catchall_1f
throw v0
:cond_22
const/4 v0, 0x0
goto :goto_1d
.end method
.method private call(Ljava/lang/Object;I)Z
.registers 4
const/4 v0, 0x0
return v0
.end method
.method private getField()Ljava/lang/Object;
.registers 2
const/4 v0, 0x0
return-object v0
.end method
.method private isZero(I)Z
.registers 3
if-nez p1, :cond_4
const/4 v0, 0x1
:goto_3
return v0
:cond_4
const/4 v0, 0x0
goto :goto_3
.end method