Make close() idempotent and fix Unicorn memory leak.

This commit is contained in:
Robert Xiao
2023-05-05 17:17:44 -07:00
parent 66c8965f96
commit 8777bb6ae6
2 changed files with 29 additions and 23 deletions

View File

@@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
package unicorn; package unicorn;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Hashtable; import java.util.Hashtable;
@@ -28,7 +29,7 @@ public class Unicorn
implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst, implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst,
MipsConst, X86Const { MipsConst, X86Const {
public long eng; private long eng;
private int arch; private int arch;
private int mode; private int mode;
@@ -70,15 +71,13 @@ public class Unicorn
private ArrayList<Tuple> syscallList = new ArrayList<Tuple>(); private ArrayList<Tuple> syscallList = new ArrayList<Tuple>();
private Hashtable<Integer, ArrayList<Tuple>> eventMemLists = private Hashtable<Integer, ArrayList<Tuple>> eventMemLists =
new Hashtable<Integer, ArrayList<Tuple>>(); new Hashtable<>();
private ArrayList<ArrayList<Tuple>> allLists = private ArrayList<ArrayList<Tuple>> allLists = new ArrayList<>();
new ArrayList<ArrayList<Tuple>>();
private static Hashtable<Integer, Integer> eventMemMap = private static Hashtable<Integer, Integer> eventMemMap = new Hashtable<>();
new Hashtable<Integer, Integer>(); private static Hashtable<Long, WeakReference<Unicorn>> unicorns =
private static Hashtable<Long, Unicorn> unicorns = new Hashtable<>();
new Hashtable<Long, Unicorn>();
// required to load native method implementations // required to load native method implementations
static { static {
@@ -107,7 +106,7 @@ public class Unicorn
* @see hook_add, unicorn.BlockHook * @see hook_add, unicorn.BlockHook
*/ */
private static void invokeBlockCallbacks(long eng, long address, int size) { private static void invokeBlockCallbacks(long eng, long address, int size) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
if (u != null) { if (u != null) {
for (Tuple p : u.blockList) { for (Tuple p : u.blockList) {
BlockHook bh = (BlockHook) p.function; BlockHook bh = (BlockHook) p.function;
@@ -126,7 +125,7 @@ public class Unicorn
* @see hook_add, unicorn.InterruptHook * @see hook_add, unicorn.InterruptHook
*/ */
private static void invokeInterruptCallbacks(long eng, int intno) { private static void invokeInterruptCallbacks(long eng, int intno) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
if (u != null) { if (u != null) {
for (Tuple p : u.intrList) { for (Tuple p : u.intrList) {
InterruptHook ih = (InterruptHook) p.function; InterruptHook ih = (InterruptHook) p.function;
@@ -146,7 +145,7 @@ public class Unicorn
* @see hook_add, unicorn.CodeHook * @see hook_add, unicorn.CodeHook
*/ */
private static void invokeCodeCallbacks(long eng, long address, int size) { private static void invokeCodeCallbacks(long eng, long address, int size) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
if (u != null) { if (u != null) {
for (Tuple p : u.codeList) { for (Tuple p : u.codeList) {
CodeHook ch = (CodeHook) p.function; CodeHook ch = (CodeHook) p.function;
@@ -174,7 +173,7 @@ public class Unicorn
private static boolean invokeEventMemCallbacks(long eng, int type, private static boolean invokeEventMemCallbacks(long eng, int type,
long address, int size, long address, int size,
long value) { long value) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
boolean result = true; boolean result = true;
if (u != null) { if (u != null) {
ArrayList<Tuple> funcList = u.eventMemLists.get(type); ArrayList<Tuple> funcList = u.eventMemLists.get(type);
@@ -199,7 +198,7 @@ public class Unicorn
* @see hook_add, unicorn.ReadHook * @see hook_add, unicorn.ReadHook
*/ */
private static void invokeReadCallbacks(long eng, long address, int size) { private static void invokeReadCallbacks(long eng, long address, int size) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
if (u != null) { if (u != null) {
for (Tuple p : u.readList) { for (Tuple p : u.readList) {
ReadHook rh = (ReadHook) p.function; ReadHook rh = (ReadHook) p.function;
@@ -221,7 +220,7 @@ public class Unicorn
*/ */
private static void invokeWriteCallbacks(long eng, long address, int size, private static void invokeWriteCallbacks(long eng, long address, int size,
long value) { long value) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
if (u != null) { if (u != null) {
for (Tuple p : u.writeList) { for (Tuple p : u.writeList) {
WriteHook wh = (WriteHook) p.function; WriteHook wh = (WriteHook) p.function;
@@ -243,7 +242,7 @@ public class Unicorn
* @see hook_add, unicorn.InHook * @see hook_add, unicorn.InHook
*/ */
private static int invokeInCallbacks(long eng, int port, int size) { private static int invokeInCallbacks(long eng, int port, int size) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
int result = 0; int result = 0;
if (u != null) { if (u != null) {
for (Tuple p : u.inList) { for (Tuple p : u.inList) {
@@ -267,7 +266,7 @@ public class Unicorn
*/ */
private static void invokeOutCallbacks(long eng, int port, int size, private static void invokeOutCallbacks(long eng, int port, int size,
int value) { int value) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
int result = 0; int result = 0;
if (u != null) { if (u != null) {
for (Tuple p : u.outList) { for (Tuple p : u.outList) {
@@ -287,7 +286,7 @@ public class Unicorn
* @see hook_add, unicorn.SyscallHook * @see hook_add, unicorn.SyscallHook
*/ */
private static void invokeSyscallCallbacks(long eng) { private static void invokeSyscallCallbacks(long eng) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng).get();
int result = 0; int result = 0;
if (u != null) { if (u != null) {
for (Tuple p : u.syscallList) { for (Tuple p : u.syscallList) {
@@ -353,7 +352,7 @@ public class Unicorn
this.arch = arch; this.arch = arch;
this.mode = mode; this.mode = mode;
eng = open(arch, mode); eng = open(arch, mode);
unicorns.put(eng, this); unicorns.put(eng, new WeakReference<>(this));
allLists.add(blockList); allLists.add(blockList);
allLists.add(intrList); allLists.add(intrList);
allLists.add(codeList); allLists.add(codeList);
@@ -369,7 +368,6 @@ public class Unicorn
* *
*/ */
protected void finalize() { protected void finalize() {
unicorns.remove(eng);
close(); close();
} }
@@ -379,7 +377,7 @@ public class Unicorn
* @return hexadecimal number as (major << 8 | minor), which encodes both major * @return hexadecimal number as (major << 8 | minor), which encodes both major
* & minor versions. * & minor versions.
* *
* For example Unicorn version 1.2 whould yield 0x0102 * For example Unicorn version 1.2 would yield 0x0102
*/ */
public native static int version(); public native static int version();
@@ -396,7 +394,15 @@ public class Unicorn
* Close the underlying uc_engine* eng associated with this Unicorn object * Close the underlying uc_engine* eng associated with this Unicorn object
* *
*/ */
public native void close() throws UnicornException; private native void _close() throws UnicornException;
public void close() throws UnicornException {
if (eng != 0) {
_close();
unicorns.remove(eng);
eng = 0;
}
}
/** /**
* Query internal status of engine. * Query internal status of engine.

View File

@@ -388,10 +388,10 @@ JNIEXPORT jboolean JNICALL Java_unicorn_Unicorn_arch_1supported(JNIEnv *env,
/* /*
* Class: unicorn_Unicorn * Class: unicorn_Unicorn
* Method: close * Method: _close
* Signature: ()V * Signature: ()V
*/ */
JNIEXPORT void JNICALL Java_unicorn_Unicorn_close(JNIEnv *env, jobject self) JNIEXPORT void JNICALL Java_unicorn_Unicorn__1close(JNIEnv *env, jobject self)
{ {
uc_engine *eng = getEngine(env, self); uc_engine *eng = getEngine(env, self);
uc_err err = uc_close(eng); uc_err err = uc_close(eng);