Decompiler / Function: mark function parameter as "unused", reflect that in decompiler #5743
Labels
Feature: Decompiler
Status: Triage
Information is being gathered
Type: Enhancement
New feature or request
Is your feature request related to a problem? Please describe.
Functions sometimes have unused arguments; if the x86_64 optimizer is aware of this it can leave the register or stack slot "uninitialized", effectively passing a random value based on prior code, to that call.
Minimally, this leads to somewhat confusing decompilation where, eg, what is clearly a
std::string
is cast to some other object type entirely (matching the unused parameter.)Earlier, when types were less clear, this back-propagated the type information from the function argument and mis-typed a whole pile of stuff because of it.
While the arguments can happen naturally, I run into this with MSVC-compiled C++ code with inlining, optimization, and templates can generate concrete function instantiations that:
This happens in "constructor with bulk construction of children" most often; the current example
DisplayWidgetConsole
, 9148 bytes of code, and creates 51 instantiations ofConsoleCommand<...>
representing the various commands that can be run. It stops inlining the template constructor instatiation at the 14thConsoleCommand<>
, 3017 (0xBC9) bytes into the function body.In other places,
NULL
is passed in that slot, despite the compiler having access to the appropriate variable to fill it, because the optimizer "knows" it is unused in the function body.(in the concrete example below, the
this
argument to astd::string
constructor was still inRCX
during the next call, so it seemed like the same thing was passed to the function twice, as two different types.)Describe the solution you'd like
In writing code, developers often adopt conventions like
void foo(void* /*unused*/, uint bar)
to flag this to other humans. This helps avoid any confusion.For the decompiler, especially in the face of the optimizer generating these, it'd be great to be able to say "use of this function parameter is irrelevant, do not consider it for any purpose in understanding the code."
Ideally, it'd end up looking like this in the decompiled code:
Describe alternatives you've considered
I was naming the parameter
__unused
or__ignored
in the function prototype for that concrete instantiation.This made the body of the function easier to understand, because I could see that I already did the work to make sure it was genuinely unused, not just "bad prototype of a called function makes it look unused."
OTOH, the decompiler back-propagated that name to local variables, and
__ignored
was often reused for meaningful values in other instantiations of the same template function.Additional context
This, along with #2573, are the two main "features of code" I associate with a function that will never stop spitting out the decompiler warning that type propagation never settled, or that it exceeded the maximum restart count.
Unused arguments are less prone to triggering that, but they seem to push functions toward it. I presume this is because the "unused" argument is treated as a valid "cast", and a stack slot suddenly changes from
std::string
toPhysicsEngine2
, a conflict that can't be resolved without ignoring the "unused" parameter.The text was updated successfully, but these errors were encountered: