Ghidra: Decompiler misinterprets `if (double_param != 0) {...}` as dead code

Created on 3 Jul 2019  路  5Comments  路  Source: NationalSecurityAgency/ghidra

Describe the bug
If a function takes a 64-bit float parameter and then proceeds to compare it to 0 (MOVSD->UCOMISD->LAHF->TEST->JNP), Ghidra considers the non-0 branch to be dead code and for parameter to be unused.

To Reproduce

  1. Compile the following DLL from a fresh unmanaged C++ DLL project in VS2019 with platform tools v142 and targeting x86:
#include "pch.h"
extern "C" __declspec(dllexport) void __cdecl test(double enable, HWND hwnd) {
    if (enable != 0) {
        MessageBoxA(hwnd, "Not 0!", "", MB_OK);
    } else {
        MessageBoxA(hwnd, "0!", "", MB_OK|MB_ICONERROR);
    }
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    return TRUE;
}
  1. Create a Ghidra project, add the DLL to it, and run analyzer with default settings
  2. Navigate to the test function in Exports and take a look at decompile view.

You get this:

void __cdecl _test(undefined4 param_1,undefined4 param_2,HWND param_3)

{
                    /* 0x1000  1  test
                       Symbol Ref: _test */
  if (false) {
    MessageBoxA(param_3,"Not 0!","",0);
    return;
  }
  MessageBoxA(param_3,"0!","",0x10);
  return;
}

(then-branch is considered to be dead code; 8-byte parameter is interpreted as two unknown4s)

Expected behavior
Recognizing MOSD/UCOMISD as a sign of the parameter being a 64-bit float, or, failing that, showing a comparison to literal's raw floating-point value.

Attachments
Pre-compiled version of the sample DLL

Environment (please complete the following information):

  • OS: Win10, build 17134
  • Java Version: 12.0.1
  • Ghidra Version: 9.0.4

Additional context
The shared trait between this and my original code is use of MOVSD+UCOMISD for value != 0 comparisons, perhaps this is the source of trouble

        10001000 55              PUSH       EBP
        10001001 8b ec           MOV        EBP,ESP
        10001003 f2 0f 10        MOVSD      XMM0,qword ptr [EBP + param_1]
                 45 08
        10001008 66 0f 2e        UCOMISD    XMM0,qword ptr [__real@0000000000000000]
                 05 b0 20 
                 00 10
        10001010 9f              LAHF
        10001011 f6 c4 44        TEST       AH,0x44
        10001014 7b 17           JNP        LAB_1000102d
...

(from sample)

Bug

Most helpful comment

This problem was caused by the parity flag not being modeled for x86. This is now fixed in master and the upcoming 9.2

All 5 comments

assume you tested with a correct prototype, does that change anything?

Hello, sorry, I forgot to include this in the issue text after moving things around - updating the function signature to match expected types doesn't seem to do anything for it,

void __cdecl _test(double val,HWND hwnd)

{
                    /* 0x1000  1  test
                       Symbol Ref: _test */
  if (false) {
    MessageBoxA(hwnd,"Not 0!","",0);
    return;
  }
  MessageBoxA(hwnd,"0!","",0x10);
  return;
}

~Ah, looks that instruction has a todo~
wish github search was better, searching for UCOMISD goes to VUCOMISD, which does have todo, but UCOMISD looks implemented

I think mine might be the same thing as this previously described issue https://github.com/NationalSecurityAgency/ghidra/issues/122

This problem was caused by the parity flag not being modeled for x86. This is now fixed in master and the upcoming 9.2

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chibicitiberiu picture chibicitiberiu  路  3Comments

lab313ru picture lab313ru  路  3Comments

CalcProgrammer1 picture CalcProgrammer1  路  3Comments

huettenhain picture huettenhain  路  3Comments

ghost picture ghost  路  3Comments