18

In nearly every dis-assembly created by IDA, there are several functions that are marked nullsub_ which according to IDA, return null nothing (just ret instruction).

So, what are those and why are they in the database?

2
  • 2
    I think that you mean "according to IDA, they return nothing" (i.e. a bare "ret" instruction). This is not the same as null. It can happen when a procedure is a placeholder, for example. Commented Jul 7, 2013 at 18:09
  • @peterferrie, you are right. Thanks for the correction.
    – PhoeniX
    Commented Jul 7, 2013 at 18:36

3 Answers 3

24

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 nullsubs 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.

9

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.

2
  • So compiler might deliberately left it, although optimization flags were on?
    – PhoeniX
    Commented Oct 10, 2013 at 6:58
  • Well not all optimizations are equal, nor are all compilers equal. The examples I'm thinking of were from non-ARM/x86 CPU's or code from the 80s/90s. Commented Oct 10, 2013 at 22:23
1

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...

1
  • Compilers -- with the exception of deliberately obfuscating compilers -- do not undertake any code generation actions specifically for the purpose of confusing disassemblers and decompilers. Commented Nov 10, 2021 at 3:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.