diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index e288f7e9a0c..29d73134118 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -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); diff --git a/librz/arch/function.c b/librz/arch/function.c index 525356fb779..c579d1c24cb 100644 --- a/librz/arch/function.c +++ b/librz/arch/function.c @@ -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 = { diff --git a/librz/core/cmd/cmd_api.c b/librz/core/cmd/cmd_api.c index f45648566ac..e3bf4f08460 100644 --- a/librz/core/cmd/cmd_api.c +++ b/librz/core/cmd/cmd_api.c @@ -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); diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index fc0b8fc802c..64daf1c6564 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -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); @@ -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; } @@ -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; } @@ -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); @@ -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); diff --git a/librz/core/rop.c b/librz/core/rop.c index 2204e14f3ad..ecb95b00c95 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -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; @@ -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); } diff --git a/librz/il/il_validate.c b/librz/il/il_validate.c index 7c5fa92c887..abbb0eb5352 100644 --- a/librz/il/il_validate.c +++ b/librz/il/il_validate.c @@ -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; @@ -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; @@ -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; @@ -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; diff --git a/librz/type/parser/types_parser.c b/librz/type/parser/types_parser.c index 78c2e20ab66..01d6dc1a03a 100644 --- a/librz/type/parser/types_parser.c +++ b/librz/type/parser/types_parser.c @@ -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) { diff --git a/librz/util/itv.c b/librz/util/itv.c index 2a424186398..9ece2f4f522 100644 --- a/librz/util/itv.c +++ b/librz/util/itv.c @@ -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"); @@ -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; } diff --git a/test/integration/meson.build b/test/integration/meson.build index e636b94b6c0..f30fced7c3b 100644 --- a/test/integration/meson.build +++ b/test/integration/meson.build @@ -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', ] diff --git a/test/integration/test_rop_cache.c b/test/integration/test_rop_cache.c new file mode 100644 index 00000000000..44c9006b6b9 --- /dev/null +++ b/test/integration/test_rop_cache.c @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2024 z3phyr +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#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) diff --git a/test/unit/test_cmd.c b/test/unit/test_cmd.c index 13a871dfc86..19f4741848b 100644 --- a/test/unit/test_cmd.c +++ b/test/unit/test_cmd.c @@ -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; } @@ -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; } diff --git a/test/unit/test_il_vm.c b/test/unit/test_il_vm.c index c5774e04c16..504d3718288 100644 --- a/test/unit/test_il_vm.c +++ b/test/unit/test_il_vm.c @@ -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, diff --git a/test/unit/test_regex.c b/test/unit/test_regex.c index 066478989ea..1c12216c9b2 100644 --- a/test/unit/test_regex.c +++ b/test/unit/test_regex.c @@ -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; } @@ -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; }