Decompiler: RuleIgnoreNan
is too aggressive when removing NaN branches
#6580
Labels
Milestone
RuleIgnoreNan
is too aggressive when removing NaN branches
#6580
Describe the bug
Sometimes, when
RuleIgnoreNan
tries to removeNaN
-branches from conditionals, it is too aggressive and also removes other branches, leading to incorrect decompiler output.To Reproduce
Steps to reproduce the behavior:
INT_OR
and zero. #6578decomp_dbg
decomp_dbg
restore /path/to/fcomp_error_constant.xml
and press enterload function FUN_0000000c
and press enterdecompile
and press enterprint C
and press enterif
statement looks likeFLOAT_00000008 == 1.5
instead ofFLOAT_00000008 <= 1.5
.Expected behavior
I expected the guard of the
if
statement to look more likeFLOAT_00000008 <= 1.5
.Attachments
fcomp_error_constant.xml
Environment
INT_OR
and zero. #6578Additional context
Looking into the problem using DecompVis, I found that the cause of this issue is an application of the rule
RuleIgnoreNan
, as shown by this screenshot. The change outlined in red is incorrect. It also removes the connection betweenZF
andr0x00000008(i) < #0x3fc00000
by detaching theu0x10000015:1
varnode fromZF
.After the change to
u0x10000015:1
, theNAN
flow has already been removed fromu0x10000015:1
, sou0x10000015:1
does not need to be removed fromZF
. In fact, removing it fromZF
is wrong, since it still contains the important flow fromr0x00000008(i) < #0x3fc00000
.Looking through the relevant code, it seems that the error is in
RuleIgnoreNan::testForComparison
. This function tests if the given binary operator (BOOL_AND
orBOOL_OR
) contains a comparison withNAN
. If so, it increments a counter and changes the binary operator to aCOPY
of the not-NAN flow. Finally, it returns the outputVarnode
of the operator.ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc
Lines 9496 to 9508 in fb844be
However, the calling code seems to interpret a non-null return value to mean "the
NAN
flow continues into thisVarnode
". If the operation was changed to aCOPY
however, theNAN
flow no longer flows into the returnedVarnode
. As such, I thinkRuleIgnoreNan::testForComparison
should return a null pointer if it changed the opcode to aCOPY
.Locally, I applied the following patch, which gives the correct output for the case above - the decompiled output now correctly uses
<=
.The text was updated successfully, but these errors were encountered: