From cfb28e5c406c33546b6c00eadafd72c5b7482c0b Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 1 Jul 2026 07:28:46 +0000 Subject: [PATCH] Fix memory leaks across arch, core, and util --- librz/arch/isa/arm/arm_esil32.c | 6 ++++-- librz/arch/isa/arm/arm_esil64.c | 4 ++-- librz/arch/p/analysis/analysis_hppa_cs.c | 11 ++++++++++- librz/core/canalysis.c | 4 ++++ librz/core/cbin.c | 1 + librz/core/cmd/cmd_analysis.c | 1 + librz/core/cmd/cmd_search.c | 3 ++- librz/core/cmd/cmd_type.c | 1 + librz/core/cmd/cmd_write.c | 4 +++- librz/core/core.c | 1 + librz/util/table.c | 7 +++++-- 11 files changed, 34 insertions(+), 9 deletions(-) diff --git a/librz/arch/isa/arm/arm_esil32.c b/librz/arch/isa/arm/arm_esil32.c index e62f4fb6042..43423eb05a5 100644 --- a/librz/arch/isa/arm/arm_esil32.c +++ b/librz/arch/isa/arm/arm_esil32.c @@ -1027,14 +1027,16 @@ RZ_IPI int rz_arm_cs_analysis_op_32_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 a break; case ARM_SFT_LSL: case ARM_SFT_LSL_REG: - rz_strf(move_esil, "%s", rz_strbuf_drain_nofree(&op->esil)); + rz_strf(move_esil, "%s", rz_strbuf_get(&op->esil)); + rz_strbuf_fini(&op->esil); rz_strbuf_appendf(&op->esil, ",%s,!,!,?{,%s,32,-,%s,>>,cf,:=,},%s", ARG(1), ARG(1), ARG(0), move_esil); break; case ARM_SFT_LSR: case ARM_SFT_LSR_REG: case ARM_SFT_ASR: case ARM_SFT_ASR_REG: - rz_strf(move_esil, "%s", rz_strbuf_drain_nofree(&op->esil)); + rz_strf(move_esil, "%s", rz_strbuf_get(&op->esil)); + rz_strbuf_fini(&op->esil); rz_strbuf_appendf(&op->esil, "%s,!,!,?{,%s,1,%s,-,0x1,<<,&,!,!,cf,:=,},%s", ARG(1), ARG(0), ARG(1), move_esil); break; } diff --git a/librz/arch/isa/arm/arm_esil64.c b/librz/arch/isa/arm/arm_esil64.c index c363378d469..ac92d90e009 100644 --- a/librz/arch/isa/arm/arm_esil64.c +++ b/librz/arch/isa/arm/arm_esil64.c @@ -971,13 +971,13 @@ RZ_IPI int rz_arm_cs_analysis_op_64_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 a postfix = ""; break; case AARCH64_INS_ALIAS_CSET: // cset Wd --> Wd := (cond) ? 1 : 0 - rz_strbuf_drain_nofree(&op->esil); + rz_strbuf_fini(&op->esil); rz_arm64_cs_esil_prefix_cond(op, AArch64CC_getInvertedCondCode(insn->detail->arm64.cc)); rz_strbuf_appendf(&op->esil, "1,}{,0,},%s,=", REG64(0)); postfix = ""; break; case AARCH64_INS_ALIAS_CINC: // cinc Wd, Wn --> Wd := (cond) ? (Wn+1) : Wn - rz_strbuf_drain_nofree(&op->esil); + rz_strbuf_fini(&op->esil); rz_arm64_cs_esil_prefix_cond(op, AArch64CC_getInvertedCondCode(insn->detail->arm64.cc)); rz_strbuf_appendf(&op->esil, "1,%s,+,}{,%s,},%s,=", REG64(1), REG64(1), REG64(0)); postfix = ""; diff --git a/librz/arch/p/analysis/analysis_hppa_cs.c b/librz/arch/p/analysis/analysis_hppa_cs.c index 73fcacf124f..2dadf2ce96f 100644 --- a/librz/arch/p/analysis/analysis_hppa_cs.c +++ b/librz/arch/p/analysis/analysis_hppa_cs.c @@ -193,16 +193,25 @@ static void hppa_fillvals(const RzAsmHPPAContext *ctx, RzAnalysis *a, RzAnalysis cs_hppa_op *hop = &hc->operands[i]; RzAnalysisValue *av = rz_analysis_value_new(); hppa_fillval(a->reg, ctx->h, av, hop); - if (hop->access & CS_AC_READ) { + bool owned = false; + if ((hop->access & CS_AC_READ) && srci < RZ_ARRAY_SIZE(op->src)) { av->access |= RZ_ANALYSIS_ACC_R; op->src[srci++] = av; + owned = true; } if (hop->access & CS_AC_WRITE) { av->access |= RZ_ANALYSIS_ACC_W; if (srci > 0 && av == op->src[srci - 1]) { av = rz_mem_dup(av, sizeof(RzAnalysisValue)); } + // a single op->dst slot: release the previous write operand + rz_analysis_value_free(op->dst); op->dst = av; + owned = true; + } + if (!owned) { + // operand is neither read nor written, so nothing takes ownership + rz_analysis_value_free(av); } } } diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 82822b9a1a7..92d9e9bc887 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -5504,11 +5504,15 @@ static void core_decoded_bytes_set_mnemonic(RzCoreDecodedBytes *cdb, bool is_x86 cdb->mnemonic = rz_str_ndup(opcode, space - opcode); } +static void analysis_bytes_iter_fini(RzCoreDecodedBytes *cdb); + static RzCoreDecodedBytes *core_decoded_bytes_next(RzIterator *it) { CoreDecodedBytes *ctx = it->u; if (!core_decoded_bytes_can_continue(ctx)) { return NULL; } + // release the data produced for the previous element before reusing the buffer + analysis_bytes_iter_fini(&ctx->cdb); static const RzAnalysisOpMask mask = RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_IL | RZ_ANALYSIS_OP_MASK_OPEX | RZ_ANALYSIS_OP_MASK_HINT; RzCore *core = ctx->core; diff --git a/librz/core/cbin.c b/librz/core/cbin.c index 9f68c004f89..5b64f72f2b0 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -3159,6 +3159,7 @@ RZ_API RZ_OWN RzPVector /**/ *rz_core_bin_whole_strings(RZ_NONNUL } rz_io_read_at_mapped(core->io, 0, tmp, bf->size); rz_buf_write_at(bf->buf, 0, tmp, bf->size); + free(tmp); } if (!core->file) { RZ_LOG_ERROR("Core file not open\n"); diff --git a/librz/core/cmd/cmd_analysis.c b/librz/core/cmd/cmd_analysis.c index ef35ce27ee2..3f9efb53541 100644 --- a/librz/core/cmd/cmd_analysis.c +++ b/librz/core/cmd/cmd_analysis.c @@ -4945,6 +4945,7 @@ static void analysis_class_print_to_json(RzAnalysis *analysis, PJ *pj, const cha pj_kn(pj, "offset", vtable->offset); pj_end(pj); } + rz_vector_free(vtables); } pj_end(pj); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 55225bc4ce3..1a3bacbb2e2 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1621,7 +1621,8 @@ static int pass_to_legacy_api(RzCore *core, int argc, const char **argv, RzOutpu for (size_t i = 1; i < argc; i++) { rz_strbuf_appendf(legacy_input, " %s", argv[i]); } - bool succeeded = cmd_search_legacy_handler(core, rz_strbuf_drain(legacy_input)); + bool succeeded = cmd_search_legacy_handler(core, rz_strbuf_get(legacy_input)); + rz_strbuf_free(legacy_input); return succeeded ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; } diff --git a/librz/core/cmd/cmd_type.c b/librz/core/cmd/cmd_type.c index 232da68bb8e..a10c30cd222 100644 --- a/librz/core/cmd/cmd_type.c +++ b/librz/core/cmd/cmd_type.c @@ -593,6 +593,7 @@ RZ_IPI RzCmdStatus rz_type_noreturn_del_all_handler(RzCore *core, int argc, cons rz_list_foreach (noretl, iter, name) { rz_type_func_noreturn_drop(typedb, name); } + rz_list_free(noretl); return RZ_CMD_STATUS_OK; } diff --git a/librz/core/cmd/cmd_write.c b/librz/core/cmd/cmd_write.c index 74e2bc41966..e412e951a83 100644 --- a/librz/core/cmd/cmd_write.c +++ b/librz/core/cmd/cmd_write.c @@ -524,7 +524,9 @@ RZ_IPI RzCmdStatus rz_write_block_handler(RzCore *core, int argc, const char **a return RZ_CMD_STATUS_ERROR; } - return bool2status(rz_core_write_block(core, core->offset, hex, len)); + RzCmdStatus status = bool2status(rz_core_write_block(core, core->offset, hex, len)); + free(hex); + return status; } RZ_IPI RzCmdStatus rz_write_mask_set_handler(RzCore *core, int argc, const char **argv) { diff --git a/librz/core/core.c b/librz/core/core.c index fcc976e22ec..aa3918a55c1 100644 --- a/librz/core/core.c +++ b/librz/core/core.c @@ -1135,6 +1135,7 @@ RZ_API char *rz_core_analysis_hasrefs_to_depth(RzCore *core, ut64 value, PJ *pj, if (pj) { pj_end(pj); } + rz_strbuf_free(s); return NULL; } diff --git a/librz/util/table.c b/librz/util/table.c index 513b44c6f28..1cf7eaf14e9 100644 --- a/librz/util/table.c +++ b/librz/util/table.c @@ -239,6 +239,7 @@ static bool table_query_select_columns(RzTable *t, const char *column_name, cons free(op); return false; } + char *name = NULL; size_t col = 0; if (table_query_resolve_column(t, column_name, &col)) { RzTableColumn *column = rz_vector_index_ptr(t->cols, col); @@ -247,7 +248,7 @@ static bool table_query_select_columns(RzTable *t, const char *column_name, cons free(op); return false; } - char *name = rz_str_dup(column->name); + name = rz_str_dup(column->name); if (!name) { rz_list_free(list); free(op); @@ -256,7 +257,7 @@ static bool table_query_select_columns(RzTable *t, const char *column_name, cons // Normalize the first selected column before passing the list to the generic selector. rz_list_prepend(list, name); } else if (RZ_STR_ISNOTEMPTY(column_name)) { - char *name = rz_str_dup(column_name); + name = rz_str_dup(column_name); if (!name) { rz_list_free(list); free(op); @@ -267,6 +268,8 @@ static bool table_query_select_columns(RzTable *t, const char *column_name, cons rz_table_columns_select(t, list); rz_list_free(list); free(op); + // the split list elements point into op; only the prepended name is owned here + free(name); return true; }