diff --git a/CREDITS.TXT b/CREDITS.TXT index db06ff6a..d10faf27 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -72,3 +72,4 @@ Philippe Antoine (Catena cyber): fuzzing Huitao Chen (chenhuitao) & KaiJern Lau (xwings): Cmake support Huitao Chen (chenhuitao) & KaiJern Lau (xwings): Python3 support for building Kevin Foo (chfl4gs): Travis-CI migration +Ziqiao Kong (lazymio): Various bug fix and improvement. \ No newline at end of file diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index b97129e4..7f76976c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -139,6 +139,7 @@ _setup_prototype(_uc, "uc_free", ucerr, ctypes.c_void_p) _setup_prototype(_uc, "uc_context_save", ucerr, uc_engine, uc_context) _setup_prototype(_uc, "uc_context_restore", ucerr, uc_engine, uc_context) _setup_prototype(_uc, "uc_context_size", ctypes.c_size_t, uc_engine) +_setup_prototype(_uc, "uc_context_free", ucerr, uc_context) _setup_prototype(_uc, "uc_mem_regions", ucerr, uc_engine, ctypes.POINTER(ctypes.POINTER(_uc_mem_region)), ctypes.POINTER(ctypes.c_uint32)) # uc_hook_add is special due to variable number of arguments @@ -661,7 +662,7 @@ class UcContext: def __del__(self): # We need this property since we shouldn't free it if the object is constructed from pickled bytes. if self._to_free: - _uc.uc_free(self._context) + _uc.uc_context_free(self._context) # print out debugging info diff --git a/include/uc_priv.h b/include/uc_priv.h index 833a4238..77773b7d 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -250,13 +250,15 @@ struct uc_struct { uint32_t target_page_align; uint64_t next_pc; // save next PC for some special cases bool hook_insert; // insert new hook at begin of the hook list (append by default) + struct list saved_contexts; // The contexts saved by this uc_struct. }; // Metadata stub for the variable-size cpu context used with uc_context_*() // We also save cpu->jmp_env, so emulation can be reentrant struct uc_context { size_t context_size; // size of the real internal context structure - unsigned int jmp_env_size; // size of cpu->jmp_env + size_t jmp_env_size; // size of cpu->jmp_env + struct uc_struct* uc; // the uc_struct which creates this context char data[0]; // context + cpu->jmp_env }; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 6b415bb2..ab5485ed 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -707,10 +707,12 @@ UNICORN_EXPORT uc_err uc_context_alloc(uc_engine *uc, uc_context **context); /* - Free the memory allocated by uc_context_alloc & uc_mem_regions. + Free the memory allocated by uc_mem_regions. + WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc should + be free-ed by uc_context_free(). Calling uc_free() may still work, but the result + is **undefined**. - @mem: memory allocated by uc_context_alloc (returned in *context), or - by uc_mem_regions (returned in *regions) + @mem: memory allocated by uc_mem_regions (returned in *regions). @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). @@ -738,7 +740,7 @@ uc_err uc_context_save(uc_engine *uc, uc_context *context); state saved by uc_context_save(). @uc: handle returned by uc_open() - @buffer: handle returned by uc_context_alloc that has been used with uc_context_save + @context: handle returned by uc_context_alloc that has been used with uc_context_save @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). @@ -758,6 +760,18 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context); UNICORN_EXPORT size_t uc_context_size(uc_engine *uc); + +/* + Free the context allocated by uc_context_alloc(). + + @context: handle returned by uc_context_alloc() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_context_free(uc_context *context); + #ifdef __cplusplus } #endif diff --git a/uc.c b/uc.c index f27a6a11..819b0bee 100644 --- a/uc.c +++ b/uc.c @@ -348,6 +348,16 @@ uc_err uc_close(uc_engine *uc) free(uc->mapped_blocks); + // free the saved contexts list and notify them that uc has been closed. + cur = uc->saved_contexts.head; + while (cur != NULL) { + struct list_item *next = cur->next; + struct uc_context *context = (struct uc_context*)cur->data; + context->uc = NULL; + cur = next; + } + list_clear(&uc->saved_contexts); + // finally, free uc itself. memset(uc, 0, sizeof(*uc)); free(uc); @@ -1327,7 +1337,12 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context) if (*_context) { (*_context)->jmp_env_size = sizeof(*uc->cpu->jmp_env); (*_context)->context_size = cpu_context_size(uc->arch, uc->mode); - return UC_ERR_OK; + (*_context)->uc = uc; + if (list_insert(&uc->saved_contexts, *_context)) { + return UC_ERR_OK; + } else { + return UC_ERR_NOMEM; + } } else { return UC_ERR_NOMEM; } @@ -1360,7 +1375,20 @@ UNICORN_EXPORT uc_err uc_context_restore(uc_engine *uc, uc_context *context) { memcpy(uc->cpu->env_ptr, context->data, context->context_size); - memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size); + if (list_exists(&uc->saved_contexts, context)) { + memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size); + } return UC_ERR_OK; } + +UNICORN_EXPORT +uc_err uc_context_free(uc_context *context) +{ + uc_engine* uc = context->uc; + // if uc is NULL, it means that uc_engine has been free-ed. + if (uc) { + list_remove(&uc->saved_contexts, context); + } + return uc_free(context); +} \ No newline at end of file