In nearly every dis-assembly created by IDA, there are several functions that are marked nullsub_
which according to IDA, return nothing (just null
ret
instruction).
So, what are those and why are they in the database?
In nearly every dis-assembly created by IDA, there are several functions that are marked nullsub_
which according to IDA, return nothing (just null
ret
instruction).
So, what are those and why are they in the database?
I'm answering from a C++ viewpoint, other languages have different reasons.
There are legitimate uses for these functions, even if they are nothing more than
void func(/* any args */) {}
One example that comes to mind is a virtual function that does nothing in a base class but is overridden in a derived class. A similar example would be a template function whose general case is empty but specializations are not.
One more case is static variables. A static variable destructor has to be called at the end of the program, which usually uses atexit
to register the destructor callback when the variable is accessed for the first time. As I recall, the C++ standard says that a destructor with no observable behaviour might not be invoked, but I have seen MSVC 6.0 register nullsub
s as destructors anyway.
Global variables follow rules similar to static ones.
Another possibility is a function that simply has no effect, according to the compiler. The function has to exist in case something (e.g. another compilation unit that doesn't know the implementation is empty) tries to call it, but its body is empty.
Mind that "according to the compiler" is not always equal to the coder's understanding. I myself once wrote a cleanup function that did a lot of work, but by mistake it took the argument by value instead of by reference. The compiler optimized the entire function body to a {}
without any warning. Oops.
DCoders answer is great, but other reasons include:
The function might have the body #ifdef'ed out in release verse debug, but the function call is left to avoid changing the flow of the code.
One example is debug print functions
Another reason is to allow for patching. This one is pretty weak.
compiler may insert dumb null_sub randomly between directions, in order to confuse IDA decompiler. So that IDA may generate meaningless variable names, increase reverse engineer's effort to understand the workflow, to connect to dots...