Fix memory leaks related to DWARF (#6245)

* fix: memory leak rz_analysis_op_fini op->src

* fix: memory leak, replaced `rz_type_clone` with `rz_type_clone_shallow` to resolve the memory leak in `rz_type_free(type.callable)`

* fix: memory leak in try_create_var_global

* fix: memory leak in dwarf

* fix: remove redundant memset calls and add documentation for rz_type_clone_shallow

* Update librz/arch/op.c

Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com>

* fix: set free and free_user to NULL in vector copy when item_cpy is not provided

---------

Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com>
This commit is contained in:
billow 2026-04-18 01:33:11 +08:00 committed by GitHub
parent 346bb6375f
commit 71aa8bf1dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 88 additions and 60 deletions

View file

@ -886,7 +886,7 @@ static RZ_OWN RzType *type_parse_from_offset_internal(
RZ_BORROW RZ_IN RZ_NONNULL RzSetU *visited) {
RzType *type = ht_up_find(ctx->analysis->debug_info->type_by_offset, offset, NULL);
if (type) {
return rz_type_clone(type);
return rz_type_clone_shallow(type);
}
if (rz_set_u_contains(visited, offset)) {
@ -1021,7 +1021,7 @@ static RZ_OWN RzType *type_parse_from_offset_internal(
break;
}
RzType *copy = type ? rz_type_clone(type) : NULL;
RzType *copy = type ? rz_type_clone_shallow(type) : NULL;
if (copy && ht_up_insert(ctx->analysis->debug_info->type_by_offset, offset, copy)) {
#if RZ_BUILD_DEBUG
char *tstring = rz_type_as_string(ctx->analysis->typedb, type);
@ -1513,7 +1513,7 @@ static bool function_children_parse(
}
if (v.kind == RZ_ANALYSIS_VAR_KIND_FORMAL_PARAMETER) {
RzCallableArg *arg = rz_type_callable_arg_new(
ctx->analysis->typedb, v.prefer_name, rz_type_clone(v.type));
ctx->analysis->typedb, v.prefer_name, rz_type_clone_shallow(v.type));
rz_type_callable_arg_add(callable, arg);
}
RzAnalysisDwarfVariable *ptr = rz_vector_push(&fn->variables, &v);
@ -1632,7 +1632,7 @@ static bool function_from_die(
}
RzCallable *callable = rz_type_callable_new(fcn->prefer_name);
callable->ret = fcn->ret_type ? rz_type_clone(fcn->ret_type) : NULL;
callable->ret = fcn->ret_type ? rz_type_clone_shallow(fcn->ret_type) : NULL;
rz_vector_init(&fcn->variables, sizeof(RzAnalysisDwarfVariable), (RzVectorFree)variable_fini, NULL);
function_children_parse(ctx, die, callable, fcn);
@ -1690,7 +1690,7 @@ static bool try_create_var_global(
RzBinDwarfLine *dw_line = rz_bin_dwarf_line(ctx->dw);
RzBinDwarfLineUnit *lu = ctx->unit && dw_line ? rz_pvector_at(dw_line->units, ctx->unit->index) : NULL;
ut64 file_index = attr ? rz_bin_dwarf_attr_udata(attr) : UT64_MAX;
const char *file = file_index != 0 && lu ? rz_bin_dwarf_file_path(ctx->dw, lu, file_index) : NULL;
char *file = file_index != 0 && lu ? rz_bin_dwarf_file_path(ctx->dw, lu, file_index) : NULL;
attr = rz_bin_dwarf_die_get_attr(die, DW_AT_decl_line);
ut32 line = attr ? rz_bin_dwarf_attr_udata(attr) : UT32_MAX;
@ -1701,6 +1701,7 @@ static bool try_create_var_global(
result = rz_analysis_var_global_create_with_sourceline(
ctx->analysis, v->prefer_name, v->type, v->location->address,
file, line, column);
free(file);
v->type = NULL;
beach:
@ -1803,26 +1804,26 @@ RZ_API void rz_analysis_dwarf_preprocess_info(
b = temp; \
} while (0)
static inline void update_base_type(const RzTypeDB *typedb, RzBaseType *type) {
RzBaseType *t = rz_type_db_get_base_type(typedb, type->name);
if (t && t == type) {
static inline void update_base_type(const RzTypeDB *typedb, RzBaseType *bt) {
RzBaseType *db_bt = rz_type_db_get_base_type(typedb, bt->name);
if (db_bt && db_bt == bt) {
return;
}
rz_type_db_update_base_type(typedb, rz_base_type_clone(type));
rz_type_db_update_base_type(typedb, rz_base_type_clone(bt));
}
static void db_save_renamed(RzTypeDB *db, RzBaseType *b, char *name) {
if (!name) {
static void db_save_renamed(RzTypeDB *db, RzBaseType *bt, char *new_name) {
if (!new_name) {
rz_warn_if_reached();
return;
}
RzBaseType *t = rz_type_db_get_base_type(db, b->name);
if (t == b) {
RzBaseType *db_bt = rz_type_db_get_base_type(db, bt->name);
if (db_bt == bt) {
return;
}
free(b->name);
b->name = name;
rz_type_db_update_base_type(db, b);
free(bt->name);
bt->name = new_name;
rz_type_db_update_base_type(db, bt);
}
static bool store_base_type(void *u, const char *k, const void *v) {
@ -2053,7 +2054,7 @@ static bool RzAnalysisDwarfVariable_as_RzAnalysisVar(RzAnalysis *a, RzAnalysisFu
if (!loc) {
return false;
}
var->type = DW_var->type ? rz_type_clone(DW_var->type) : rz_type_new_default(a->typedb);
var->type = DW_var->type ? rz_type_clone_shallow(DW_var->type) : rz_type_new_default(a->typedb);
var->name = rz_str_dup(DW_var->prefer_name ? DW_var->prefer_name : "");
var->kind = DW_var->kind;
var->fcn = f;
@ -2120,6 +2121,7 @@ RZ_API RzAnalysisDebugInfo *rz_analysis_debug_info_new() {
debug_info->type_by_offset = ht_up_new(NULL, (HtUPFreeValue)rz_type_free);
debug_info->callable_by_offset = ht_up_new(NULL, (HtUPFreeValue)rz_type_callable_free);
debug_info->base_type_by_offset = ht_up_new(NULL, (HtUPFreeValue)rz_type_base_type_free);
// just for by name lookup, we don't store the same base type pointer here, so no need to free value
debug_info->base_types_by_name = ht_sp_new(HT_STR_DUP, NULL, (HtSPFreeValue)rz_pvector_free);
debug_info->visited = rz_set_u_new();
return debug_info;

View file

@ -38,12 +38,10 @@ RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op) {
if (!op) {
return false;
}
rz_analysis_value_free(op->src[0]);
rz_analysis_value_free(op->src[1]);
rz_analysis_value_free(op->src[2]);
op->src[0] = NULL;
op->src[1] = NULL;
op->src[2] = NULL;
for (size_t i = 0; i < RZ_ARRAY_SIZE(op->src); ++i) {
rz_analysis_value_free(op->src[i]);
op->src[i] = NULL;
}
rz_analysis_value_free(op->dst);
op->dst = NULL;
rz_list_free(op->access);

View file

@ -1184,8 +1184,9 @@ static void tricore_fillvals(RzAsmTriCoreContext *ctx, RzAnalysis *a, RzAnalysis
av->access |= RZ_ANALYSIS_ACC_W;
if (op->dst) {
rz_warn_if_reached();
continue;
}
if (srci > 0 && av == op->src[srci - 1]) {
if (top->access & CS_AC_READ) {
av = rz_mem_dup(av, sizeof(RzAnalysisValue));
}
op->dst = av;

View file

@ -263,7 +263,7 @@ static char *full_file_path(
* \param index the index of the file
* \return the full path or NULL if the file index is invalid
*/
RZ_API char *rz_bin_dwarf_file_path(RZ_NONNULL RZ_BORROW RzBinDWARF *dw,
RZ_API RZ_OWN char *rz_bin_dwarf_file_path(RZ_NONNULL RZ_BORROW RzBinDWARF *dw,
RZ_NONNULL RZ_BORROW RzBinDwarfLineUnit *lu, ut64 index) {
rz_return_val_if_fail(dw && lu, NULL);
return full_file_path(dw, &lu->hdr, index);

View file

@ -847,12 +847,12 @@ static bool Evaluation_evaluate_one_operation(
goto err;
}
Value clone = { 0 };
if (!Value_clone_into(value, &clone) &&
if (Value_clone_into(value, &clone) &&
Evaluation_push(self, &clone)) {
Value_fini(&clone);
goto err;
break;
}
break;
Value_fini(&clone);
goto err;
}
case OPERATION_KIND_SWAP: {
Value a = { 0 };
@ -1092,6 +1092,7 @@ static bool Evaluation_evaluate_one_operation(
out->kind = OperationEvaluationResult_COMPLETE;
if (val1.type == RzBinDwarfValueType_LOCATION) {
MEM_CPY(Location, &out->complete, val1.location);
rz_bin_dwarf_location_free(val1.location);
} else {
out->complete.kind = RzBinDwarfLocationKind_VALUE;
MEM_CPY(Value, &out->complete.value, &val1);
@ -1412,6 +1413,7 @@ RZ_API RZ_OWN RzBinDwarfLocation *rz_bin_dwarf_location_from_block(
}
RzBinDwarfEvaluation *eval = NULL;
RzBinDwarfEvaluationResult *result = NULL;
Location *loc = RZ_NEW0(Location);
if (!loc) {
return NULL;
@ -1424,23 +1426,27 @@ RZ_API RZ_OWN RzBinDwarfLocation *rz_bin_dwarf_location_from_block(
if (rz_bin_dwarf_block_empty(block)) {
loc->kind = RzBinDwarfLocationKind_EMPTY;
} else {
RzBinDwarfEvaluationResult *result = RZ_NEW0(RzBinDwarfEvaluationResult);
RET_NULL_IF_FAIL(result);
result = RZ_NEW0(RzBinDwarfEvaluationResult);
ERR_IF_FAIL(result);
eval = rz_bin_dwarf_evaluation_new_from_block(&R, dw, unit, die);
ERR_IF_FAIL(eval);
if (!(rz_bin_dwarf_evaluation_evaluate(eval, result) &&
RzBinDwarfEvaluationResult_to_loc(eval, result, loc))) {
goto err;
};
}
}
return loc;
err:
if (eval && eval->state.kind == EVALUATION_STATE_DECODE_ERROR) {
loc->kind = RzBinDwarfLocationKind_DECODE_ERROR;
if (eval) {
if (eval->state.kind == EVALUATION_STATE_DECODE_ERROR) {
loc->kind = RzBinDwarfLocationKind_DECODE_ERROR;
}
} else {
rz_bin_dwarf_location_free(loc);
loc = NULL;
}
rz_bin_dwarf_evaluation_free(eval);
RzBinDwarfEvaluationResult_free(result);
return loc;
}

View file

@ -1006,8 +1006,8 @@ RZ_IPI void Value_fini(RzBinDwarfValue *self) {
}
if (self->type == RzBinDwarfValueType_LOCATION) {
rz_bin_dwarf_location_free(self->location);
self->location = NULL;
}
memset(self, 0, sizeof(RzBinDwarfValue));
}
RZ_IPI void Value_free(RzBinDwarfValue *self) {

View file

@ -1579,7 +1579,6 @@ static bool analysis_block_cb(RzAnalysisBlock *bb, BlockRecurseCtx *ctx) {
}
RzAnalysisOp *op = rz_core_analysis_op(core, pos, RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_VAL | RZ_ANALYSIS_OP_MASK_HINT);
if (!op) {
// eprintf ("Cannot get op\n");
break;
}
rz_analysis_extract_rarg(core->analysis, op, fcn, reg_set, &ctx->count);

View file

@ -1766,7 +1766,8 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, RzCmdStateOutput *state)
RzStrBuf sb = { 0 };
rz_strbuf_init(&sb);
rz_bin_dwarf_dump(dw, &sb);
rz_cons_strcat(rz_strbuf_drain_nofree(&sb));
rz_cons_strcat(rz_strbuf_get(&sb));
rz_strbuf_fini(&sb);
}
RzBinDwarfLine *line = rz_bin_dwarf_line(dw);
if (line && line->lines) {

View file

@ -1539,7 +1539,7 @@ RZ_API void rz_bin_dwarf_line_free(RZ_OWN RZ_NULLABLE RzBinDwarfLine *li);
RZ_API void rz_bin_dwarf_line_units_dump(
RZ_NONNULL RZ_BORROW RzBinDwarfLine *line,
RZ_NONNULL RZ_BORROW RzStrBuf *sb);
RZ_API char *rz_bin_dwarf_file_path(RZ_NONNULL RZ_BORROW RzBinDWARF *dw,
RZ_API RZ_OWN char *rz_bin_dwarf_file_path(RZ_NONNULL RZ_BORROW RzBinDWARF *dw,
RZ_NONNULL RZ_BORROW RzBinDwarfLineUnit *lu, ut64 index);
/// dwarf

View file

@ -298,6 +298,7 @@ RZ_API RZ_BORROW RzType *rz_type_db_base_type_unwrap_typedef(RZ_NONNULL const Rz
// Compound types
RZ_API RZ_OWN RzType *rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type);
RZ_API RZ_OWN RzType *rz_type_clone_shallow(RZ_BORROW RZ_NONNULL const RzType *type);
RZ_API RZ_BORROW const char *rz_type_identifier(RZ_NONNULL const RzType *type);
RZ_API bool rz_types_equal(RZ_NONNULL const RzType *type1, RZ_NONNULL const RzType *type2);
RZ_API RZ_OWN char *rz_type_as_string(const RzTypeDB *typedb, RZ_NONNULL const RzType *type);

View file

@ -130,7 +130,7 @@ static void RzTypeStructMember_cpy(RzTypeStructMember *dst, RzTypeStructMember *
}
memcpy(dst, src, sizeof(RzTypeStructMember));
dst->name = rz_str_dup(src->name);
dst->type = rz_type_clone(src->type);
dst->type = rz_type_clone_shallow(src->type);
}
static void RzTypeEnumCase_cpy(RzTypeEnumCase *dst, RzTypeEnumCase *src) {
@ -147,7 +147,7 @@ static void RzTypeUnionMember_cpy(RzTypeUnionMember *dst, RzTypeUnionMember *src
}
memcpy(dst, src, sizeof(RzTypeUnionMember));
dst->name = rz_str_dup(src->name);
dst->type = rz_type_clone(src->type);
dst->type = rz_type_clone_shallow(src->type);
}
/**
@ -162,7 +162,7 @@ RZ_API bool rz_base_type_clone_into(
rz_return_val_if_fail(src && dst, false);
rz_mem_copy(dst, sizeof(RzBaseType), src, sizeof(RzBaseType));
dst->name = rz_str_dup(src->name);
dst->type = src->type ? rz_type_clone(src->type) : NULL;
dst->type = src->type ? rz_type_clone_shallow(src->type) : NULL;
switch (src->kind) {
case RZ_BASE_TYPE_KIND_ENUM:
@ -191,15 +191,15 @@ RZ_API RZ_OWN RzBaseType *rz_base_type_clone(RZ_NULLABLE RZ_BORROW RzBaseType *b
if (!b) {
return NULL;
}
RzBaseType *type = RZ_NEW0(RzBaseType);
if (!type) {
RzBaseType *bt = RZ_NEW0(RzBaseType);
if (!bt) {
return NULL;
}
if (!rz_base_type_clone_into(type, b)) {
rz_type_base_type_free(type);
if (!rz_base_type_clone_into(bt, b)) {
rz_type_base_type_free(bt);
return NULL;
}
return type;
return bt;
}
/**

View file

@ -36,7 +36,7 @@ RZ_API RZ_OWN RzCallable *rz_type_callable_clone(RZ_BORROW RZ_NONNULL const RzCa
if (!newcallable) {
return NULL;
}
newcallable->ret = callable->ret ? rz_type_clone(callable->ret) : NULL;
newcallable->ret = callable->ret ? rz_type_clone_shallow(callable->ret) : NULL;
newcallable->name = rz_str_dup(callable->name);
newcallable->args = rz_pvector_new((RzPVectorFree)rz_type_callable_arg_free);
void **it;
@ -90,7 +90,7 @@ RZ_API RZ_OWN RzCallableArg *rz_type_callable_arg_clone(RZ_BORROW RZ_NONNULL con
return NULL;
}
newarg->name = rz_str_dup(arg->name);
newarg->type = rz_type_clone(arg->type);
newarg->type = rz_type_clone_shallow(arg->type);
return newarg;
}
@ -366,7 +366,7 @@ RZ_API bool rz_type_func_ret_set(RzTypeDB *typedb, const char *name, RZ_BORROW R
return false;
}
rz_type_free(callable->ret);
callable->ret = rz_type_clone(type);
callable->ret = rz_type_clone_shallow(type);
return true;
}

View file

@ -1161,12 +1161,7 @@ RZ_API RZ_BORROW const char *rz_type_identifier(RZ_NONNULL const RzType *type) {
return NULL;
}
/**
* \brief Creates an exact clone of the RzType
*
* \param type RzType pointer
*/
RZ_API RZ_OWN RzType *rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type) {
static RZ_OWN RzType *type_clone(RZ_BORROW RZ_NONNULL const RzType *type, const bool clone_callable) {
rz_return_val_if_fail(type, NULL);
RzType *newtype = RZ_NEW0(RzType);
if (!newtype) {
@ -1182,21 +1177,41 @@ RZ_API RZ_OWN RzType *rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type) {
case RZ_TYPE_KIND_ARRAY:
newtype->kind = RZ_TYPE_KIND_ARRAY;
newtype->array.count = type->array.count;
newtype->array.type = rz_type_clone(type->array.type);
newtype->array.type = type_clone(type->array.type, clone_callable);
break;
case RZ_TYPE_KIND_POINTER:
newtype->kind = RZ_TYPE_KIND_POINTER;
newtype->pointer.is_const = type->pointer.is_const;
newtype->pointer.type = rz_type_clone(type->pointer.type);
newtype->pointer.type = type_clone(type->pointer.type, clone_callable);
break;
case RZ_TYPE_KIND_CALLABLE:
newtype->kind = RZ_TYPE_KIND_CALLABLE;
newtype->callable = rz_type_callable_clone(type->callable);
newtype->callable = clone_callable ? rz_type_callable_clone(type->callable) : type->callable;
break;
}
return newtype;
}
/**
* \brief Creates a shallow clone of the RzType, i.e. the callables are shared between the original and the cloned type
* \param type RzType pointer
* \return clone of the RzType
*/
RZ_API RZ_OWN RzType *rz_type_clone_shallow(RZ_BORROW RZ_NONNULL const RzType *type) {
rz_return_val_if_fail(type, NULL);
return type_clone(type, false);
}
/**
* \brief Creates an exact clone of the RzType
*
* \param type RzType pointer
*/
RZ_API RZ_OWN RzType *rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type) {
rz_return_val_if_fail(type, NULL);
return type_clone(type, true);
}
/**
* \brief Checks if two types are identical
*

View file

@ -98,8 +98,13 @@ RZ_API bool rz_vector_clone_intof(
dst->capacity = src->capacity;
dst->len = src->len;
dst->elem_size = src->elem_size;
dst->free = NULL;
dst->free_user = NULL;
if (item_cpy) {
dst->free = src->free;
dst->free_user = src->free_user;
} else {
dst->free = NULL;
dst->free_user = NULL;
}
if (!dst->len) {
dst->a = NULL;
} else {