binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

Propogate type (Q) should apply NamedTypeReference instead of the bare structure type itself

Open xusheng6 opened this issue 3 months ago • 7 comments

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?

xusheng6 avatar Sep 12 '25 07:09 xusheng6

"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>

xusheng6 avatar Sep 12 '25 07:09 xusheng6

Database: exquisite token formats safely

Repro:

  1. Open database
  2. Select the call to _func at 0x10000038c
  3. Press Q on it
  4. Notice the type of the _func becomes void _func(struct struct_1* arg1)
  5. 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'>

xusheng6 avatar Sep 12 '25 08:09 xusheng6

Interestlingly, the current behavior also leads to inferior decompilation output:

Image

If the pointer to NTR is applied, there is no redundancy:

Image

xusheng6 avatar Sep 12 '25 08:09 xusheng6

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:

Image

xusheng6 avatar Sep 12 '25 08:09 xusheng6

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

xusheng6 avatar Sep 12 '25 08:09 xusheng6

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

xusheng6 avatar Sep 12 '25 08:09 xusheng6

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

xusheng6 avatar Sep 16 '25 07:09 xusheng6