Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions librz/arch/analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ RZ_API RzAnalysis *rz_analysis_free(RzAnalysis *a) {
rz_str_constpool_fini(&a->constpool);
ht_sp_free(a->ht_global_var);
ht_up_free(a->ht_rop_semantics);
ht_up_free(a->ht_rop);
ht_sp_free(a->plugins);
rz_analysis_debug_info_free(a->debug_info);
ht_sp_free(a->ht_virtual_xrefs);
Expand Down
2 changes: 1 addition & 1 deletion librz/arch/function.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ RZ_API bool rz_analysis_function_relocate(RzAnalysisFunction *fcn, ut64 addr) {
RzAnalysisVar *var = *it;
RzAnalysisVarAccess *acc;
rz_vector_foreach (&var->accesses, acc) {
acc->offset -= delta;
acc->offset = (st64)((ut64)acc->offset - (ut64)delta);
}
}
InstVarsRelocateCtx ctx = {
Expand Down
7 changes: 6 additions & 1 deletion librz/core/cmd/cmd_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,12 @@ static RzCmdDesc *create_cmd_desc(RzCmd *cmd, RzCmdDesc *parent, RzCmdDescType t
RZ_LOG_WARN("Command already in hash table. Previous command has been replaced.\n");
goto err;
}
cmd_desc_set_parent(cmd, res, parent);
if (!cmd_desc_set_parent(cmd, res, parent)) {
if (ht_insert) {
ht_sp_delete(cmd->ht_cmds, name);
}
goto err;
}
return res;
err:
cmd_desc_free(res);
Expand Down
9 changes: 5 additions & 4 deletions librz/core/cmd/cmd_search_rop.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai

skip_whitespace(str, &idx);

RzList *args = rz_list_new();
RzList *args = rz_list_newf(free); // Fix memory leak: Auto-free elements
bool is_compound_op = false;
if (!parse_il_op(args, str, &idx, &is_compound_op)) {
free(src_reg);
Expand Down Expand Up @@ -283,7 +283,7 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai

const char *op_str = rz_il_op_pure_code_stringify(*op);
rop_constraint->args[OP] = rz_str_dup(op_str);
rop_constraint->args[SRC_REG_SECOND] = strdup(dst_reg1);
rop_constraint->args[SRC_REG_SECOND] = dst_reg1;
rz_list_free(args);
return true;
}
Expand Down Expand Up @@ -362,6 +362,7 @@ static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstrain

if (!parse_eof(str, idx)) {
free(dst_reg);
free(src_reg); // Fix memory leak
return false;
}

Expand All @@ -388,7 +389,7 @@ static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstra
free(dst_reg);
goto compound;
}
RzList *args = rz_list_new();
RzList *args = rz_list_newf(free); // Fix memory leak: Auto-free elements
if (!parse_il_op(args, str, &idx, NULL)) {
free(dst_reg);
free(src_reg);
Expand Down Expand Up @@ -512,7 +513,7 @@ static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstrain
goto compound;
}

RzList *args = rz_list_new();
RzList *args = rz_list_newf(free); // Fix memory leak: Auto-free elements
if (!args || !parse_il_op(args, str, &idx, NULL)) {
free(dst_reg);
free(src_reg1);
Expand Down
25 changes: 25 additions & 0 deletions librz/core/rop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1878,6 +1878,19 @@ static int handle_rop_search_address(RzCore *core, RzRopSearchContext *context,
RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context) {
rz_return_val_if_fail(core && core->search && context, RZ_CMD_STATUS_ERROR);

if (context->cache && context->greparg && *context->greparg) {
if (!core->analysis->ht_rop) {
core->analysis->ht_rop = ht_up_new(NULL, free);
}
ut64 cache_key = rz_str_djb2_hash(context->greparg);
char *cached_result = ht_up_find(core->analysis->ht_rop, cache_key, NULL);
if (cached_result) {
rz_cons_print(cached_result);
return RZ_CMD_STATUS_OK;
}
context->ret_val = true;
}

RzInterval search_itv = { 0 };
if (!fetch_search_itv(core, &search_itv)) {
return RZ_CMD_STATUS_ERROR;
Expand Down Expand Up @@ -1944,6 +1957,18 @@ RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopS
eprintf("\n");
}

if (context->cache && context->greparg && *context->greparg && context->buf) {
ut64 cache_key = rz_str_djb2_hash(context->greparg);
char *result = rz_strbuf_drain(context->buf);
context->buf = NULL;
if (result && *result) {
ht_up_insert(core->analysis->ht_rop, cache_key, result);
rz_cons_print(result);
} else {
free(result);
}
}

if (context->state) {
rz_cmd_state_output_array_end(context->state);
}
Expand Down
66 changes: 49 additions & 17 deletions librz/il/il_validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,16 @@ VALIDATOR_PURE(ite) {
VALIDATOR_DESCEND(args->x, &sx);
RzILSortPure sy;
VALIDATOR_DESCEND(args->y, &sy);
VALIDATOR_ASSERT(rz_il_sort_pure_eq(sx, sy), "Types of ite branches do not agree: %s vs. %s.\n",
rz_il_sort_pure_stringify(sx),
rz_il_sort_pure_stringify(sy));
if (!rz_il_sort_pure_eq(sx, sy)) {
char *sxs = rz_il_sort_pure_stringify(sx);
char *sys = rz_il_sort_pure_stringify(sy);
rz_warn_if_reached();
rz_strbuf_appendf(report_builder, "Types of ite branches do not agree: %s vs. %s.\n",
rz_str_get_null(sxs), rz_str_get_null(sys));
free(sxs);
free(sys);
return false;
}

*sort_out = sx;
return true;
Expand Down Expand Up @@ -606,10 +613,18 @@ VALIDATOR_PURE(forder) {
VALIDATOR_ASSERT(sy.type == RZ_IL_TYPE_PURE_FLOAT, "Right operand of %s op is not a float.\n", rz_il_op_pure_code_stringify(op->code));

// flatten validator assert
VALIDATOR_ASSERT(sx.props.f.format == sy.props.f.format, "Op %s formats of left operand (%s) and right operand (%s) do not agree.\n",
rz_il_op_pure_code_stringify(op->code),
rz_il_sort_pure_stringify(sx),
rz_il_sort_pure_stringify(sy));
if (sx.props.f.format != sy.props.f.format) {
char *sxs = rz_il_sort_pure_stringify(sx);
char *sys = rz_il_sort_pure_stringify(sy);
rz_warn_if_reached();
rz_strbuf_appendf(report_builder, "Op %s formats of left operand (%s) and right operand (%s) do not agree.\n",
rz_il_op_pure_code_stringify(op->code),
rz_str_get_null(sxs),
rz_str_get_null(sys));
free(sxs);
free(sys);
return false;
}

*sort_out = rz_il_sort_pure_bool();
return true;
Expand Down Expand Up @@ -652,10 +667,18 @@ VALIDATOR_PURE(float_binop_with_round) {
VALIDATOR_ASSERT(sy.type == RZ_IL_TYPE_PURE_FLOAT, "Right operand of %s op is not a float.\n", rz_il_op_pure_code_stringify(op->code));

// flatten validator assert
VALIDATOR_ASSERT(sx.props.f.format == sy.props.f.format, "Op %s formats of left operand (%s) and right operand (%s) do not agree.\n",
rz_il_op_pure_code_stringify(op->code),
rz_il_sort_pure_stringify(sx),
rz_il_sort_pure_stringify(sy));
if (sx.props.f.format != sy.props.f.format) {
char *sxs = rz_il_sort_pure_stringify(sx);
char *sys = rz_il_sort_pure_stringify(sy);
rz_warn_if_reached();
rz_strbuf_appendf(report_builder, "Op %s formats of left operand (%s) and right operand (%s) do not agree.\n",
rz_il_op_pure_code_stringify(op->code),
rz_str_get_null(sxs),
rz_str_get_null(sys));
free(sxs);
free(sys);
return false;
}

*sort_out = sx;
return true;
Expand All @@ -674,12 +697,21 @@ VALIDATOR_PURE(float_terop_with_round) {
VALIDATOR_DESCEND(args->z, &sz);
VALIDATOR_ASSERT(sz.type == RZ_IL_TYPE_PURE_FLOAT, "3rd operand of %s op is not a float.\n", rz_il_op_pure_code_stringify(op->code));

VALIDATOR_ASSERT((sx.props.f.format == sy.props.f.format) && (sx.props.f.format == sz.props.f.format),
"types of operand in op %s do not agree: operand1 (%s) operand2 (%s) operand3 (%s)",
rz_il_op_pure_code_stringify(op->code),
rz_il_sort_pure_stringify(sx),
rz_il_sort_pure_stringify(sy),
rz_il_sort_pure_stringify(sz));
if (!((sx.props.f.format == sy.props.f.format) && (sx.props.f.format == sz.props.f.format))) {
char *sxs = rz_il_sort_pure_stringify(sx);
char *sys = rz_il_sort_pure_stringify(sy);
char *szs = rz_il_sort_pure_stringify(sz);
rz_warn_if_reached();
rz_strbuf_appendf(report_builder, "types of operand in op %s do not agree: operand1 (%s) operand2 (%s) operand3 (%s)",
rz_il_op_pure_code_stringify(op->code),
rz_str_get_null(sxs),
rz_str_get_null(sys),
rz_str_get_null(szs));
free(sxs);
free(sys);
free(szs);
return false;
}

*sort_out = sx;
return true;
Expand Down
7 changes: 6 additions & 1 deletion librz/type/parser/types_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,12 @@ int parse_struct_node(CParserState *state, TSNode node, const char *text, Parser
}
field_declarator = ts_node_next_named_sibling(field_declarator);
} while (!ts_node_is_null(field_declarator));
free(membtpair);
if (membtpair) {
if (membtpair->type) {
rz_type_free(membtpair->type);
}
free(membtpair);
}
}
// If parsing successfull completed - we store the state
if (struct_pair) {
Expand Down
4 changes: 3 additions & 1 deletion librz/util/itv.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ RZ_API bool rz_itv_str_to_bounded_itv_ut64(RZ_NONNULL const char *itv_str, RZ_OU
if (num == 0 && itv_str[0] != '0') {
RZ_LOG_ERROR("Failed to parse: '%s'.\n", itv_str);
rz_pvector_free(matches);
rz_regex_free(re_interval); // Fix memory leak
return false;
}
out_itv->a = num;
out_itv->b = num;
out_itv->bound = RZ_INTERVAL_BOUND_CLOSED;
rz_regex_free(re_interval);
return true;
}
int lb_group = rz_regex_get_group_idx_by_name(re_interval, "left_bound");
Expand Down Expand Up @@ -98,6 +100,6 @@ RZ_API bool rz_itv_str_to_bounded_itv_ut64(RZ_NONNULL const char *itv_str, RZ_OU

error:
rz_pvector_free(matches);
rz_regex_free(re_interval);
rz_regex_free(re_interval); // Fix memory leak
return false;
}
1 change: 1 addition & 0 deletions test/integration/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ if get_option('enable_tests') and cli_enabled
'open_analyse_save_load_project',
'pdb',
'project_migrate',
'rop_cache',
'rzpipe',
'str_search',
]
Expand Down
78 changes: 78 additions & 0 deletions test/integration/test_rop_cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: 2024 z3phyr <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_core.h>
#include <rz_rop.h>
#include "../unit/minunit.h"

bool test_rop_cache(void) {
RzCore *core = rz_core_new();
mu_assert_notnull(core, "core");

#if __WINDOWS__
const char *test_bin = "bins/pe/standard.exe";
#else
const char *test_bin = "bins/elf/analysis/hello-linux-x86_64";
#endif

RzCoreFile *cf = rz_core_file_open(core, test_bin, RZ_PERM_RX, 0);
mu_assert_notnull(cf, "open file");
rz_core_bin_load(core, NULL, 0);
rz_config_set_b(core->config, "rop.cache", true);

RzCmdStateOutput state;
rz_cmd_state_output_init(&state, RZ_OUTPUT_MODE_QUIET, core);

RzRopSearchContext *ctx = rz_core_rop_search_context_new(
core, "", false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, &state);
rz_core_rop_search(core, ctx);
rz_core_rop_search_context_free(ctx);

if (core->analysis->ht_rop) {
mu_assert_eq(core->analysis->ht_rop->count, 0, "empty filter not cached");
}

const char *filter = "ret";
ut64 key = rz_str_djb2_hash(filter);

ctx = rz_core_rop_search_context_new(
core, filter, false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, &state);
rz_core_rop_search(core, ctx);
rz_core_rop_search_context_free(ctx);

mu_assert_notnull(core->analysis->ht_rop, "ht_rop");
char *result = ht_up_find(core->analysis->ht_rop, key, NULL);
mu_assert_notnull(result, "cached result");

ctx = rz_core_rop_search_context_new(
core, filter, false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, &state);
rz_core_rop_search(core, ctx);
rz_core_rop_search_context_free(ctx);

char *result2 = ht_up_find(core->analysis->ht_rop, key, NULL);
mu_assert_ptreq(result2, result, "cache hit");

const char *filter2 = "pop";
ut64 key2 = rz_str_djb2_hash(filter2);

ctx = rz_core_rop_search_context_new(
core, filter2, false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, &state);
rz_core_rop_search(core, ctx);
rz_core_rop_search_context_free(ctx);

char *result3 = ht_up_find(core->analysis->ht_rop, key2, NULL);
mu_assert_notnull(result3, "pop cached");
mu_assert_ptrneq(result3, result, "different cache entries");
mu_assert_eq(core->analysis->ht_rop->count, 2, "cache count");

rz_cmd_state_output_fini(&state);
rz_core_free(core);
mu_end;
}

bool all_tests() {
mu_run_test(test_rop_cache);
return tests_passed != tests_run;
}

mu_main(all_tests)
2 changes: 2 additions & 0 deletions test/unit/test_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ bool test_call_macros(void) {
mu_assert_eq(status, RZ_CMD_STATUS_NONEXISTINGCMD, "c command should not exist");

rz_cmd_free(cmd);
free(core);
mu_end;
}

Expand Down Expand Up @@ -1427,6 +1428,7 @@ bool test_call_multiple_macros(void) {
status = rz_cmd_macro_call(cmd, "macro2", macro_args_val_wrong);
mu_assert_eq(status, RZ_CMD_STATUS_INVALID, "macro2 should be called with a multiple of arguments");
rz_cmd_free(cmd);
free(core);
mu_end;
}

Expand Down
1 change: 1 addition & 0 deletions test/unit/test_il_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ static bool test_rzil_vm_op_fexcept() {
mu_assert_true(e->b, "div by zero exception should be set");
rz_float_free(result);
rz_il_op_pure_free(eop);
rz_il_bool_free(e);

// 2. Test overflow
op = rz_il_op_new_fmul(RZ_FLOAT_RMODE_RNE,
Expand Down
4 changes: 2 additions & 2 deletions test/unit/test_regex.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ bool test_rz_regex_match_all_native_utf16(void) {
mu_assert_eq(match->len, 4, "match.len wrong");

rz_pvector_free(matches);

free(utf16_he);
rz_regex_free(re);
mu_end;
}
Expand Down Expand Up @@ -394,7 +394,7 @@ bool test_rz_regex_match_all_native_utf32(void) {
mu_assert_eq(match->len, 3, "match.len wrong");

rz_pvector_free(matches);

free(utf32_he);
rz_regex_free(re);
mu_end;
}
Expand Down