Igor’s Tip of the Week #126: Non-returning functions

Some functions in programs do not return to caller: well-known examples include C runtime functions like exit(), abort(), assert() but also many others. Modern compilers can exploit this knowledge to optimize the code better: for example, the code which would normally follow such a function call does not need to be generated which decreases the program size. Other functions, which call non-returning functions unconditionally also become non-returning, which can lead to further optimizations.

Well-known functions

IDA uses function names to mark well-known non-returning functions. The list of such names is stored in the file cfg/noret.cfg, which can be edited to add more names if necessary:

Marking non-returning functions manually

Instead of editing noret.cfg, you can also mark a function as non-returning manually on a case-by-case basis. This can be done by editing function properties: Edit > Functions > Edit Function… in the main menu, Edit Function… in the context menu or the AltP shortcut.

Another option is to edit the function’s prototype and add the __noreturn keyword.

Identifying no-return calls

Incorrectly identified non-returning calls may lead to various problems during analysis: functions being truncated too early; decompiled pseudocode missing big parts of the function and so on. One option is to inspect each function being called to see if it has the Does not return flag set (or Attributes: noreturn mentioned in a comment) but this can take a long time with many calls. So there are indicators which may be easier to spot:

  • In the text view, look for dashed line after a call; it indicates a break in the code flow which means that the execution does not continue after the call, i.e. it does not return.
  • In the graph view, when a node which ends with a call has no outgoing edge, this means that the call does not return.
  • In the pseudocode it’s not always obvious, but calls to no-ret functions usually end a compound statement or the whole function. You can also switch to the disassembly if the function looks suspiciously short and look for the above tell-tales.

Enabling or disabling no-return analysis

If you find that IDA’s treatment of non-returning functions does not work well with your specific binary or set of binaries, you can turn it off. This can be done in the first set of the analysis options at the initial load time or afterwards. Conversely, you can enable it for processors which do not enable it by default.

If you need to permanently enable or disable it for all new databases, edit the ANALYSIS value in ida.cfg to include or not the AF_ANORET flag. NB: you should edit the value under #ifdef for the specific processor you need.

See also: IDA Help: Function flags