From 3c6113cd66ef8cf7e2f818342292efc8ef5947a4 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 2 Apr 2026 21:40:00 +0200 Subject: [PATCH] Reset abstract state instead of freeing and allocating it. --- librz/include/rz_inquiry/rz_interpreter.h | 7 ++- librz/inquiry/interpreter/interpreter.c | 26 ++++++---- .../interpreter/p/interpreter_prototype.c | 48 ++++++++++++++++++- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/librz/include/rz_inquiry/rz_interpreter.h b/librz/include/rz_inquiry/rz_interpreter.h index f01ee348a4..cf9077ebac 100644 --- a/librz/include/rz_inquiry/rz_interpreter.h +++ b/librz/include/rz_inquiry/rz_interpreter.h @@ -159,11 +159,16 @@ typedef struct { */ RzInterpreterYieldKind supported_yields; bool (*init)(void **plugin_data); + bool (*reset)(void *plugin_data); bool (*fini)(void *plugin_data); /** * \brief Initializes the abstract state. */ - bool (*init_state)(RZ_BORROW RzInterpreterAbstrState *state, ut64 entry_point, void *plugin_data); + bool (*init_state)(RZ_BORROW RzInterpreterAbstrState *state, void *plugin_data); + /** + * \brief Reset the abstract state. + */ + bool (*reset_state)(RZ_BORROW RzInterpreterAbstrState *state, ut64 entry_point, void *plugin_data); /** * \brief Closes the abstract state and frees all its abstract data and sets the pointers to NULL. */ diff --git a/librz/inquiry/interpreter/interpreter.c b/librz/inquiry/interpreter/interpreter.c index a70d5b79a7..324f7772db 100644 --- a/librz/inquiry/interpreter/interpreter.c +++ b/librz/inquiry/interpreter/interpreter.c @@ -422,18 +422,18 @@ static bool choose_next_pc(RzInterpreterSet *iset, return has_succsessor; } -static bool setup_intrpr_state( +static bool reset_intrpr_state( RzInterpreterSet *iset, ut64 entry_point, RzVector **tmp_succ_addr, RzSetU **reachable_states, RzVector **succ_states) { - if (iset->plugin->init) { - iset->plugin->init(&iset->intrpr_priv); + if (iset->plugin->reset) { + iset->plugin->reset(iset->intrpr_priv); } - if (!iset->plugin->init_state(iset->astate, entry_point, iset->intrpr_priv)) { + if (!iset->plugin->reset_state(iset->astate, entry_point, iset->intrpr_priv)) { rz_warn_if_reached(); return false; } @@ -485,6 +485,14 @@ RZ_API bool rz_interpreter_run(RZ_NONNULL RZ_OWN RzInterpreterSet *iset) { const RzInterpreterILBB *il_bb = NULL; ut64 astate_hash = 0; + if (iset->plugin->init) { + iset->plugin->init(&iset->intrpr_priv); + } + if (!iset->plugin->init_state(iset->astate, iset->intrpr_priv)) { + rz_warn_if_reached(); + return false; + } + // TODO: It is probably better to make the following stuff while-loops. // Because otherwise it doesn't make sense without the docs. // But while debugging and developing, I keep it this way to separate clearly @@ -501,7 +509,7 @@ INIT: { } // Initializes the current interpreter's private data and its state. - if (!setup_intrpr_state(iset, il_bb->bb_addr, &tmp_succ_addr, &reachable_states, &succ_states)) { + if (!reset_intrpr_state(iset, il_bb->bb_addr, &tmp_succ_addr, &reachable_states, &succ_states)) { success = false; goto TERM; } @@ -565,10 +573,6 @@ CLEAN: { RZ_FREE_CUSTOM(tmp_succ_addr, rz_vector_free); RZ_FREE_CUSTOM(succ_states, rz_vector_free); RZ_FREE_CUSTOM(reachable_states, rz_set_u_free); - iset->plugin->fini_state(iset->astate, iset->intrpr_priv); - if (iset->plugin->fini && iset->intrpr_priv) { - RZ_FREE_CUSTOM(iset->intrpr_priv, iset->plugin->fini); - } // Wait until RzInquiry asks to start again. rz_th_sem_wait(iset->run_state_sync); @@ -580,6 +584,10 @@ CLEAN: { TERM: { RZ_LOG_DEBUG("Enter TERM\n"); rz_intp_run_state_set(iset->run_state, RZ_INTP_RUN_STATE_TERM); + iset->plugin->fini_state(iset->astate, iset->intrpr_priv); + if (iset->plugin->fini && iset->intrpr_priv) { + RZ_FREE_CUSTOM(iset->intrpr_priv, iset->plugin->fini); + } RZ_FREE_CUSTOM(tmp_succ_addr, rz_vector_free); RZ_FREE_CUSTOM(succ_states, rz_vector_free); diff --git a/librz/inquiry/interpreter/p/interpreter_prototype.c b/librz/inquiry/interpreter/p/interpreter_prototype.c index b436a7acf7..8c1d461dd7 100644 --- a/librz/inquiry/interpreter/p/interpreter_prototype.c +++ b/librz/inquiry/interpreter/p/interpreter_prototype.c @@ -8,6 +8,7 @@ #include "../prototype/eval.h" #include "rz_util/ht_uu.h" +#include "rz_util/rz_bitvector.h" #define MAX_INVOCATIONS_PER_BB 3 @@ -80,9 +81,9 @@ bool successors(RZ_NONNULL const RzInterpreterAbstrState *state, return true; } -static bool init_state(RZ_BORROW RzInterpreterAbstrState *state, ut64 entry_point, void *plugin_data) { +static bool init_state(RZ_BORROW RzInterpreterAbstrState *state, void *plugin_data) { state->pc->abstr_data = RZ_NEW0(ProtoIntrprAbstrData); - AD(state->pc->abstr_data)->bv = rz_bv_new_from_ut64(state->il_config->mem_key_size, entry_point); + AD(state->pc->abstr_data)->bv = rz_bv_new_from_ut64(state->il_config->mem_key_size, 0); AD(state->pc->abstr_data)->is_concrete = true; RzIterator *it = ht_up_as_iter_keys(state->globals); ut64 *k; @@ -117,6 +118,36 @@ static bool init_state(RZ_BORROW RzInterpreterAbstrState *state, ut64 entry_poin return true; } +static bool reset_state(RZ_BORROW RzInterpreterAbstrState *state, ut64 entry_point, void *plugin_data) { + rz_bv_set_from_ut64(AD(state->pc->abstr_data)->bv, entry_point); + AD(state->pc->abstr_data)->is_concrete = true; + + RzIterator *it = ht_up_as_iter_keys(state->globals); + ut64 *k; + rz_iterator_foreach(it, k) { + ut64 djb2_reg_name = *k; + RzInterpreterAbstrVal *av = ht_up_find(state->globals, djb2_reg_name, NULL); + rz_bv_set_from_ut64(AD(av->abstr_data)->bv, 0); + AD(av->abstr_data)->is_concrete = true; + if (state->il_config->init_state) { + RzAnalysisILInitStateVar *il_var; + rz_vector_foreach (&state->il_config->init_state->vars, il_var) { + if (rz_str_djb2_hash(il_var->name) != djb2_reg_name) { + continue; + } + // The RzArch plugin defined a default value for this global. + RzBitVector *default_val = rz_il_value_to_bv(il_var->val); + rz_bv_copy(AD(av->abstr_data)->bv, default_val); + rz_bv_free(default_val); + } + } + } + rz_iterator_free(it); + state->bb_addr = 0; + state->bb_size = 0; + return true; +} + static bool fini_state(RZ_BORROW RzInterpreterAbstrState *state, void *plugin_data) { ProtoIntrprAbstrData *ad = state->pc->abstr_data; if (ad && ad->bv) { @@ -240,6 +271,17 @@ bool fini(void *plugin_data) { return true; } +bool reset(void *plugin_data) { + if (!plugin_data) { + return true; + } + RZ_LOG_DEBUG("prototype: reset()\n"); + ProtoIntrprPluginData *pdata = plugin_data; + ht_uu_clear(pdata->bb_invocation_count); + memset(&pdata->call_cand, 0, sizeof(RzAnalysisCallCandidate)); + return true; +} + static RzInterpreterPlugin rz_interpreter_plugin_prototype = { .name = "abstr_int_prototype", .author = "Rot127", @@ -249,10 +291,12 @@ static RzInterpreterPlugin rz_interpreter_plugin_prototype = { .supported_abstractions = RZ_INTERPRETER_ABSTRACTION_CONST, .supported_yields = RZ_INTERPRETER_YIELD_KIND_XREF | RZ_INTERPRETER_YIELD_KIND_CALL_CANDIDATE, .init = init, + .reset = reset, .fini = fini, .eval = eval, .successors = successors, .init_state = init_state, + .reset_state = reset_state, .fini_state = fini_state, .hash_state = hash_state, .set_pc = set_pc,