Skip to content

Commit 2a84e33

Browse files
committed
Fix possible leak in hooks
1 parent 9ff335e commit 2a84e33

File tree

3 files changed

+57
-34
lines changed

3 files changed

+57
-34
lines changed

include/list.h

+3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33

44
#include "unicorn/platform.h"
55

6+
typedef void (*delete_fn)(void *data);
7+
68
struct list_item {
79
struct list_item *next;
810
void *data;
911
};
1012

1113
struct list {
1214
struct list_item *head, *tail;
15+
delete_fn delete_fn;
1316
};
1417

1518
// create a new list

list.c

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ void list_clear(struct list *list)
1515
struct list_item *next, *cur = list->head;
1616
while (cur != NULL) {
1717
next = cur->next;
18+
if (list->delete_fn) {
19+
list->delete_fn(cur->data);
20+
}
1821
free(cur);
1922
cur = next;
2023
}
@@ -82,6 +85,9 @@ bool list_remove(struct list *list, void *data)
8285
if (cur == list->tail) {
8386
list->tail = prev;
8487
}
88+
if (list->delete_fn) {
89+
list->delete_fn(cur->data);
90+
}
8591
free(cur);
8692
return true;
8793
}

uc.c

+48-34
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,37 @@
2828
#include "qemu/include/qemu/queue.h"
2929
#include "qemu-common.h"
3030

31+
static void clear_deleted_hooks(uc_engine *uc);
32+
33+
static void *hook_insert(struct list *l, struct hook *h)
34+
{
35+
void *item = list_insert(l, (void *)h);
36+
if (item) {
37+
h->refs++;
38+
}
39+
return item;
40+
}
41+
42+
static void *hook_append(struct list *l, struct hook *h)
43+
{
44+
void *item = list_append(l, (void *)h);
45+
if (item) {
46+
h->refs++;
47+
}
48+
return item;
49+
}
50+
51+
static void hook_delete(void *data)
52+
{
53+
struct hook *h = (struct hook *)data;
54+
55+
h->refs--;
56+
57+
if (h->refs == 0) {
58+
free(h);
59+
}
60+
}
61+
3162
UNICORN_EXPORT
3263
unsigned int uc_version(unsigned int *major, unsigned int *minor)
3364
{
@@ -172,6 +203,12 @@ static uc_err uc_init(uc_engine *uc)
172203
return UC_ERR_HANDLE;
173204
}
174205

206+
uc->hooks_to_del.delete_fn = hook_delete;
207+
208+
for (int i = 0; i < UC_HOOK_MAX; i++) {
209+
uc->hook[i].delete_fn = hook_delete;
210+
}
211+
175212
uc->exits = g_tree_new_full(uc_exits_cmp, NULL, g_free, NULL);
176213

177214
if (machine_initialize(uc)) {
@@ -369,8 +406,6 @@ UNICORN_EXPORT
369406
uc_err uc_close(uc_engine *uc)
370407
{
371408
int i;
372-
struct list_item *cur;
373-
struct hook *hook;
374409
MemoryRegion *mr;
375410

376411
if (!uc->init_done) {
@@ -422,17 +457,9 @@ uc_err uc_close(uc_engine *uc)
422457
}
423458

424459
// free hooks and hook lists
460+
clear_deleted_hooks(uc);
461+
425462
for (i = 0; i < UC_HOOK_MAX; i++) {
426-
cur = uc->hook[i].head;
427-
// hook can be in more than one list
428-
// so we refcount to know when to free
429-
while (cur) {
430-
hook = (struct hook *)cur->data;
431-
if (--hook->refs == 0) {
432-
free(hook);
433-
}
434-
cur = cur->next;
435-
}
436463
list_clear(&uc->hook[i]);
437464
}
438465

@@ -670,12 +697,6 @@ static void clear_deleted_hooks(uc_engine *uc)
670697
assert(hook->to_delete);
671698
for (i = 0; i < UC_HOOK_MAX; i++) {
672699
if (list_remove(&uc->hook[i], (void *)hook)) {
673-
if (--hook->refs == 0) {
674-
uc->del_inline_hook(uc, hook);
675-
free(hook);
676-
}
677-
678-
// a hook cannot be twice in the same list
679700
break;
680701
}
681702
}
@@ -1507,19 +1528,18 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
15071528
}
15081529

15091530
if (uc->hook_insert) {
1510-
if (list_insert(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
1531+
if (hook_insert(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
15111532
free(hook);
15121533
return UC_ERR_NOMEM;
15131534
}
15141535
} else {
1515-
if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
1536+
if (hook_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
15161537
free(hook);
15171538
return UC_ERR_NOMEM;
15181539
}
15191540
}
15201541

15211542
uc->hooks_count[UC_HOOK_INSN_IDX]++;
1522-
hook->refs++;
15231543
return UC_ERR_OK;
15241544
}
15251545

@@ -1539,19 +1559,18 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
15391559
}
15401560

15411561
if (uc->hook_insert) {
1542-
if (list_insert(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
1562+
if (hook_insert(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
15431563
free(hook);
15441564
return UC_ERR_NOMEM;
15451565
}
15461566
} else {
1547-
if (list_append(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
1567+
if (hook_append(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
15481568
free(hook);
15491569
return UC_ERR_NOMEM;
15501570
}
15511571
}
15521572

15531573
uc->hooks_count[UC_HOOK_TCG_OPCODE_IDX]++;
1554-
hook->refs++;
15551574
return UC_ERR_OK;
15561575
}
15571576

@@ -1560,22 +1579,17 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
15601579
// TODO: invalid hook error?
15611580
if (i < UC_HOOK_MAX) {
15621581
if (uc->hook_insert) {
1563-
if (list_insert(&uc->hook[i], hook) == NULL) {
1564-
if (hook->refs == 0) {
1565-
free(hook);
1566-
}
1582+
if (hook_insert(&uc->hook[i], hook) == NULL) {
1583+
free(hook);
15671584
return UC_ERR_NOMEM;
15681585
}
15691586
} else {
1570-
if (list_append(&uc->hook[i], hook) == NULL) {
1571-
if (hook->refs == 0) {
1572-
free(hook);
1573-
}
1587+
if (hook_append(&uc->hook[i], hook) == NULL) {
1588+
free(hook);
15741589
return UC_ERR_NOMEM;
15751590
}
15761591
}
15771592
uc->hooks_count[i]++;
1578-
hook->refs++;
15791593
}
15801594
}
15811595
i++;
@@ -1607,7 +1621,7 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
16071621
if (list_exists(&uc->hook[i], (void *)hook)) {
16081622
hook->to_delete = true;
16091623
uc->hooks_count[i]--;
1610-
list_append(&uc->hooks_to_del, hook);
1624+
hook_append(&uc->hooks_to_del, hook);
16111625
}
16121626
}
16131627

0 commit comments

Comments
 (0)