diff --git a/decompiler/pipeline/commons/expressionpropagationcommons.py b/decompiler/pipeline/commons/expressionpropagationcommons.py index 36c57c14b..c9e95f4ff 100644 --- a/decompiler/pipeline/commons/expressionpropagationcommons.py +++ b/decompiler/pipeline/commons/expressionpropagationcommons.py @@ -225,8 +225,9 @@ def _is_address_into_dereference(self, definition: Assignment, target: Instructi if self._is_address(definition.value): for subexpr in target: for sub in self._find_subexpressions(subexpr): - if self._is_dereference(sub) and sub.operand == definition.destination: + if self._is_dereference(sub) and sub.operand in definition.definitions: return True + return False def _contains_aliased_variables(self, definition: Assignment) -> bool: """ @@ -326,14 +327,13 @@ def _has_any_of_dangerous_uses_between_definition_and_target( def _get_dangerous_uses_of_variable_address(self, var: Variable) -> Set[Instruction]: """ Dangerous use of & of x is func(&x) cause it can potentially modify x. - *(&x) could also do the job but I consider it to be too exotic so that we could get such instruction from Binary Ninja - If it happens we can handle it later. + Another case is an Assignment where the left side is *(&). :param var: aliased variable :return: set of function call assignments that take &var as parameter """ dangerous_uses = set() for use in self._use_map.get(var): - if not self._is_call_assignment(use): + if not self._is_call_assignment(use) and not (isinstance(use, Assignment) and self._is_dereference(use.destination)): continue for subexpr in self._find_subexpressions(use): if self._is_address(subexpr): diff --git a/tests/pipeline/dataflowanalysis/test_expression_propagation_mem.py b/tests/pipeline/dataflowanalysis/test_expression_propagation_mem.py index 5e6f4d124..b4c0fa0d0 100644 --- a/tests/pipeline/dataflowanalysis/test_expression_propagation_mem.py +++ b/tests/pipeline/dataflowanalysis/test_expression_propagation_mem.py @@ -1676,6 +1676,44 @@ def test_correct_propagation_relation(): ] +def test_address_into_dereference(): + """ + Test with cast in destination (x#0 stays the same type) + +---------------------+ + | 0. | + | (long) x#0 = &(x#1) | + | *(x#0) = x#0 | + +---------------------+ + + +---------------------+ + | 0. | + | (long) x#0 = &(x#1) | + | *(x#0) = x#0 | + +---------------------+ + """ + input_cfg, output_cfg = graphs_addr_into_deref() + _run_expression_propagation(input_cfg) + assert _graphs_equal(input_cfg, output_cfg) + + +def graphs_addr_into_deref(): + x = vars("x", 2) + c = const(10) + in_n0 = BasicBlock( + 0, + [_assign(_cast(int64, x[0]), _addr(x[1])), _assign(_deref(x[0]), x[0])], + ) + in_cfg = ControlFlowGraph() + in_cfg.add_node(in_n0) + out_n0 = BasicBlock( + 0, + [_assign(_cast(int64, x[0]), _addr(x[1])), _assign(_deref(x[0]), x[0])], + ) + out_cfg = ControlFlowGraph() + out_cfg.add_node(out_n0) + return in_cfg, out_cfg + + def graphs_with_no_propagation_of_contraction_address_assignment(): x = vars("x", 3) ptr = vars("ptr", 1, type=Pointer(int32))