Reset abstract state instead of freeing and allocating it.

This commit is contained in:
Rot127 2026-04-02 21:40:00 +02:00
parent 8650b9fcc1
commit 3c6113cd66
No known key found for this signature in database
GPG key ID: 0E088203E6CF0BA5
3 changed files with 69 additions and 12 deletions

View file

@ -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.
*/

View file

@ -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);

View file

@ -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,