From 3c0735f268ffd6f51d68a3dd3bdabac0900ec095 Mon Sep 17 00:00:00 2001 From: Priyanshu Kumar Date: Wed, 19 Aug 2026 20:21:58 +0530 Subject: [PATCH] Resolve typedefs before measuring pointer width ##types A typedef like "typedef char *string" is a pointer with no star in its name, so r_anal_type_bitsize measured it from the sdb instead of using the target word size. Resolve the typedef chain first and fail closed on cycles. --- libr/anal/type.c | 11 +++++++++-- test/unit/test_anal_types.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/libr/anal/type.c b/libr/anal/type.c index 9bf779bcd8..5fbac14658 100644 --- a/libr/anal/type.c +++ b/libr/anal/type.c @@ -157,10 +157,17 @@ R_API void r_anal_types_load_sdb(RAnal *anal, const char *name) { load_types_from (anal, "%s", name); } -// for pointers prefer the live target width over the one baked into the type sdb +// a pointer is one target word wide, which r_type_get_bitsize cannot know from the sdb alone R_API ut64 r_anal_type_bitsize(RAnal *anal, const char *type) { R_RETURN_VAL_IF_FAIL (anal && anal->config && type, 0); - return strchr (type, '*')? anal->config->bits: r_type_get_bitsize (anal->sdb_types, type); + // resolve first: "typedef char *string" is a pointer with no star in its name + char *resolved = r_type_resolve_typedef (anal->sdb_types, type); + const char *effective = resolved? resolved: type; + const ut64 bits = strchr (effective, '*') + ? anal->config->bits + : r_type_get_bitsize (anal->sdb_types, type); + free (resolved); + return bits; } R_API void r_anal_remove_parsed_type(RAnal *anal, const char *name) { diff --git a/test/unit/test_anal_types.c b/test/unit/test_anal_types.c index 85748b3a58..31dfefa313 100644 --- a/test/unit/test_anal_types.c +++ b/test/unit/test_anal_types.c @@ -321,6 +321,26 @@ static bool test_anal_get_base_type_typedef(void) { mu_assert_eq (R_ANAL_BASE_TYPE_KIND_TYPEDEF, base->kind, "Wrong base type"); mu_assert_streq (base->name, "string", "type name"); mu_assert_streq (base->type, "char *", "typedefd type"); + anal->config->bits = 64; + mu_assert_eq (r_anal_type_bitsize (anal, "string"), 64, + "Pointer typedef uses the current architecture width"); + sdb_set (anal->sdb_types, "word", "typedef", 0); + sdb_set (anal->sdb_types, "typedef.word", "unsigned long", 0); + sdb_num_set (anal->sdb_types, "type.word.size", 64, 0); + mu_assert_eq (r_anal_type_bitsize (anal, "word"), 64, + "Scalar typedef uses its exact declared width"); + sdb_set (anal->sdb_types, "cycle_a", "typedef", 0); + sdb_set (anal->sdb_types, "typedef.cycle_a", "cycle_b", 0); + sdb_set (anal->sdb_types, "cycle_b", "typedef", 0); + sdb_set (anal->sdb_types, "typedef.cycle_b", "cycle_a", 0); + sdb_set (anal->sdb_types, "u64", "type", 0); + sdb_num_set (anal->sdb_types, "type.u64.size", 64, 0); + sdb_set (anal->sdb_types, "myword", "typedef", 0); + sdb_set (anal->sdb_types, "typedef.myword", "u64", 0); + mu_assert_eq (r_type_get_bitsize (anal->sdb_types, "myword"), 64, + "Typedef without a declared width measures what it aliases"); + mu_assert_eq (r_anal_type_bitsize (anal, "cycle_a"), 0, + "Cyclic typedefs fail closed"); sdb_set (anal->sdb_types, "word", "typedef", 0); sdb_set (anal->sdb_types, "typedef.word", "unsigned long", 0);