Propogate type (Q) should apply NamedTypeReference instead of the bare structure type itself
Discussed in https://github.com/Vector35/binaryninja-api/discussions/7350
Originally posted by cafeed28 September 5, 2025 when i change the struct definition, function decompilation still remembers old definition and using them. reanalyzing function or entire database does not help, i have to reapply the type to update decompilation
https://github.com/user-attachments/assets/c8645055-0ec7-4da3-ac18-27a834ff9360
is there a way to somehow refresh all decompilations in the database?
"this is such a common pattern of breakage that we should fix it in SetUserType/SetAutoType. By walking the incoming type and ensuring that any of the type present use their NTR instead.
So pseudo code of what I'm saying:"
def SetUserType(newType)
foreach member in newType.members
if member.type is not NTR and member.type has_attribute registered_name:
member.type = bv.get_ntr(member.registered_name)
<old set user type code>
Database: exquisite token formats safely
Repro:
- Open database
- Select the call to
_funcat 0x10000038c - Press Q on it
- Notice the type of the
_funcbecomesvoid _func(struct struct_1* arg1) - Check from the Python console that the type is a pointer to the raw structure, not a pointer to the NTR:
>>> current_function.parameter_vars[0].type.target
<type: immutable:StructureTypeClass 'struct struct_1'>
Conversely, if I have manually set the type of arg1 to struct_1*, it would be a NRT:
>>> current_function.parameter_vars[0].type.target
<type: immutable:NamedTypeReferenceClass 'struct struct_1'>
Interestlingly, the current behavior also leads to inferior decompilation output:
If the pointer to NTR is applied, there is no redundancy:
I think the forward type actually does nothing wrong -- it just takes whatever the type is and forward that into the callee. The problem appears to be that the type of the &var20 is a pointer to a raw struct, rather than a pointer to a NTR:
>>> current_il_instruction.params[0]
<HighLevelILAddressOf: &var_20>
>>> current_il_instruction.params[0].expr_index
19
>>> current_il_function.get_expr_type(19)
<type: immutable:PointerTypeClass 'struct struct_1*'>
>>> current_il_function.get_expr_type(19).target
<type: immutable:StructureTypeClass 'struct struct_1'>
Screenshot of the code for completeness:
And the type of the variable var_20 itself is a NTR:
>>> current_variable.type
<type: immutable:NamedTypeReferenceClass 'struct struct_1'>
Not sure why we discarded the NTR when we take the pointer of it
Hmmm, I am totally confused -- when I drop to MLIL, at 2 @ 10000036c x0 = &var_20, the left side is actually a ptr to a NTR (which is good), and the type of the right side is a ptr to the raw struct (which is bad), but the type of the left probably had come from the left, so I am not sure how that is even possible
I have unassigned myself from it because this is more complex than expected, and we do not yet have a perfect way to fix this