Fix possible leak in hooks
This commit is contained in:
parent
9ff335efdc
commit
2a84e33f03
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicorn/platform.h"
|
#include "unicorn/platform.h"
|
||||||
|
|
||||||
|
typedef void (*delete_fn)(void *data);
|
||||||
|
|
||||||
struct list_item {
|
struct list_item {
|
||||||
struct list_item *next;
|
struct list_item *next;
|
||||||
void *data;
|
void *data;
|
||||||
@ -10,6 +12,7 @@ struct list_item {
|
|||||||
|
|
||||||
struct list {
|
struct list {
|
||||||
struct list_item *head, *tail;
|
struct list_item *head, *tail;
|
||||||
|
delete_fn delete_fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
// create a new list
|
// create a new list
|
||||||
|
6
list.c
6
list.c
@ -15,6 +15,9 @@ void list_clear(struct list *list)
|
|||||||
struct list_item *next, *cur = list->head;
|
struct list_item *next, *cur = list->head;
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
next = cur->next;
|
next = cur->next;
|
||||||
|
if (list->delete_fn) {
|
||||||
|
list->delete_fn(cur->data);
|
||||||
|
}
|
||||||
free(cur);
|
free(cur);
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
@ -82,6 +85,9 @@ bool list_remove(struct list *list, void *data)
|
|||||||
if (cur == list->tail) {
|
if (cur == list->tail) {
|
||||||
list->tail = prev;
|
list->tail = prev;
|
||||||
}
|
}
|
||||||
|
if (list->delete_fn) {
|
||||||
|
list->delete_fn(cur->data);
|
||||||
|
}
|
||||||
free(cur);
|
free(cur);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
82
uc.c
82
uc.c
@ -28,6 +28,37 @@
|
|||||||
#include "qemu/include/qemu/queue.h"
|
#include "qemu/include/qemu/queue.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
|
||||||
|
static void clear_deleted_hooks(uc_engine *uc);
|
||||||
|
|
||||||
|
static void *hook_insert(struct list *l, struct hook *h)
|
||||||
|
{
|
||||||
|
void *item = list_insert(l, (void *)h);
|
||||||
|
if (item) {
|
||||||
|
h->refs++;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *hook_append(struct list *l, struct hook *h)
|
||||||
|
{
|
||||||
|
void *item = list_append(l, (void *)h);
|
||||||
|
if (item) {
|
||||||
|
h->refs++;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hook_delete(void *data)
|
||||||
|
{
|
||||||
|
struct hook *h = (struct hook *)data;
|
||||||
|
|
||||||
|
h->refs--;
|
||||||
|
|
||||||
|
if (h->refs == 0) {
|
||||||
|
free(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
||||||
{
|
{
|
||||||
@ -172,6 +203,12 @@ static uc_err uc_init(uc_engine *uc)
|
|||||||
return UC_ERR_HANDLE;
|
return UC_ERR_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uc->hooks_to_del.delete_fn = hook_delete;
|
||||||
|
|
||||||
|
for (int i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
|
uc->hook[i].delete_fn = hook_delete;
|
||||||
|
}
|
||||||
|
|
||||||
uc->exits = g_tree_new_full(uc_exits_cmp, NULL, g_free, NULL);
|
uc->exits = g_tree_new_full(uc_exits_cmp, NULL, g_free, NULL);
|
||||||
|
|
||||||
if (machine_initialize(uc)) {
|
if (machine_initialize(uc)) {
|
||||||
@ -369,8 +406,6 @@ UNICORN_EXPORT
|
|||||||
uc_err uc_close(uc_engine *uc)
|
uc_err uc_close(uc_engine *uc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct list_item *cur;
|
|
||||||
struct hook *hook;
|
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
if (!uc->init_done) {
|
if (!uc->init_done) {
|
||||||
@ -422,17 +457,9 @@ uc_err uc_close(uc_engine *uc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free hooks and hook lists
|
// free hooks and hook lists
|
||||||
|
clear_deleted_hooks(uc);
|
||||||
|
|
||||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
cur = uc->hook[i].head;
|
|
||||||
// hook can be in more than one list
|
|
||||||
// so we refcount to know when to free
|
|
||||||
while (cur) {
|
|
||||||
hook = (struct hook *)cur->data;
|
|
||||||
if (--hook->refs == 0) {
|
|
||||||
free(hook);
|
|
||||||
}
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
list_clear(&uc->hook[i]);
|
list_clear(&uc->hook[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,12 +697,6 @@ static void clear_deleted_hooks(uc_engine *uc)
|
|||||||
assert(hook->to_delete);
|
assert(hook->to_delete);
|
||||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
if (list_remove(&uc->hook[i], (void *)hook)) {
|
if (list_remove(&uc->hook[i], (void *)hook)) {
|
||||||
if (--hook->refs == 0) {
|
|
||||||
uc->del_inline_hook(uc, hook);
|
|
||||||
free(hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a hook cannot be twice in the same list
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1507,19 +1528,18 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uc->hook_insert) {
|
if (uc->hook_insert) {
|
||||||
if (list_insert(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
if (hook_insert(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
||||||
free(hook);
|
free(hook);
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
if (hook_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
||||||
free(hook);
|
free(hook);
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uc->hooks_count[UC_HOOK_INSN_IDX]++;
|
uc->hooks_count[UC_HOOK_INSN_IDX]++;
|
||||||
hook->refs++;
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1539,19 +1559,18 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uc->hook_insert) {
|
if (uc->hook_insert) {
|
||||||
if (list_insert(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
|
if (hook_insert(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
|
||||||
free(hook);
|
free(hook);
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (list_append(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
|
if (hook_append(&uc->hook[UC_HOOK_TCG_OPCODE_IDX], hook) == NULL) {
|
||||||
free(hook);
|
free(hook);
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uc->hooks_count[UC_HOOK_TCG_OPCODE_IDX]++;
|
uc->hooks_count[UC_HOOK_TCG_OPCODE_IDX]++;
|
||||||
hook->refs++;
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1560,22 +1579,17 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
|||||||
// TODO: invalid hook error?
|
// TODO: invalid hook error?
|
||||||
if (i < UC_HOOK_MAX) {
|
if (i < UC_HOOK_MAX) {
|
||||||
if (uc->hook_insert) {
|
if (uc->hook_insert) {
|
||||||
if (list_insert(&uc->hook[i], hook) == NULL) {
|
if (hook_insert(&uc->hook[i], hook) == NULL) {
|
||||||
if (hook->refs == 0) {
|
free(hook);
|
||||||
free(hook);
|
|
||||||
}
|
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (list_append(&uc->hook[i], hook) == NULL) {
|
if (hook_append(&uc->hook[i], hook) == NULL) {
|
||||||
if (hook->refs == 0) {
|
free(hook);
|
||||||
free(hook);
|
|
||||||
}
|
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uc->hooks_count[i]++;
|
uc->hooks_count[i]++;
|
||||||
hook->refs++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@ -1607,7 +1621,7 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
|||||||
if (list_exists(&uc->hook[i], (void *)hook)) {
|
if (list_exists(&uc->hook[i], (void *)hook)) {
|
||||||
hook->to_delete = true;
|
hook->to_delete = true;
|
||||||
uc->hooks_count[i]--;
|
uc->hooks_count[i]--;
|
||||||
list_append(&uc->hooks_to_del, hook);
|
hook_append(&uc->hooks_to_del, hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user