Nested Functions in Xcode

This technote explains how to port code which uses nested functions, a GCC extension to the C language. Nested functions are not supported in Xcode 2.2.





Introduction

This technote explains how to port code which uses nested functions, a GCC extension to the C language which is not supported in Xcode 2.2. A future Xcode release will introduce a compiler switch, -fnested-functions, and a corresponding build setting to enable the feature for backwards compatibility. However, nested functions will continue to be disabled by default. Use of the backwards compatibility mode should be avoided, since it will prevent your application from taking advantage of a security feature in Mac OS X.

This technote is directed at application developers who have discovered that after installing Xcode 2.2, their application fails to build with the error "nested functions are not supported on MacOSX". If you are not getting this error, your code does not use nested functions and you do not need to read this technote (unless your application uses GNU Autoconf; see "Nested Functions and GNU Autoconf" below.)

Back to Top 

About Nested Functions

Nested functions are a GCC extension to the C language which allows you to declare a function inside another function. For instance:

    void x(int a) {
        int b;
        ...
        void y() {
            ...
        }
        ...
    }

In the example above, the function y() can only be called from inside the function x. It can access any variables which are in scope in x, such as a and b.

Nested functions are not very widely used. In a survey of 2500 open-source applications taken from the Fink project, only 6 made use of the feature.

In order to support nested functions, the compiler needed to generate code in a form which could, in certain scenarios, impact the security of the system by using a technique called stack trampolines. Stack trampolines require stack pages to be executable; this increases an application's vulnerability to buffer overflow attacks. Because it was not feasible to securely provide support for nested functions, this support was removed from the compiler in Xcode 2.2. Furthermore, removing nested functions from your code will often lead to performance improvements.

Back to Top 

Modifying Your Application

Xcode will flag all nested functions with the nested function error message when you try to build your application. To unnest these functions, take any nested functions and move them outside and above the body of the function they're inside. You may need to change the names of some formerly nested functions to avoid conflicting with other functions in your application. For instance, change:

    void x() {
        void y() { ... }
    }

to:

    void y() { ... }
    void x() { ... }

Now try building your application again. If it builds successfully, that's all you need to do. On the other hand, you may get error messages inside your formerly nested functions about variables being undeclared (for instance, "error: 'foo' undeclared (first use in this function.") This will happen when the nested function accessed variables local to its parent function. In that case, add the variables as new parameters to the function. Because the function may modify the values, you'll need to pass them by reference, through pointers. For instance, change:

    void x(int a) {
        int b;
        void y(int c) { ... }
        y(1);
    }

to:


    void y(int c, int *a, int *b) { ... }
    void x(int a) {
        int b;
        y(1,  &a, &b);
    }

Make sure you update your formerly nested functions to take into account that a and b are now pointers to integers instead of simply integers!

If you know certain things about how the two functions act regarding the variables local to the original function which are now parameters of the new function, there are some optimizations you can make. If the outer function doesn't care about any changes in the value of one of these variables which take place within the nested function, it isn't necessary to pass it in to the new function by reference, so in the example above, a or b in y could be type int instead of int * if we knew this about them. If the inner function never modifies the value at all, you can add the const modifier, e.g. const int a.

Back to Top 

Another Example

Listing 1: Without nested functions

  int factorial(int num) {
    int total = 1, b;

    int multiply() {
      return total * b;
    }

    int updateTotal() {
      total = multiply();
    }

    for(b = 1; b <= num; b++) {
      updateTotal();
    }

    return total;
  }

Listing 2: With nested functions

  //multiply doesn't modify either total or b, so
  //we don't need to pass them through pointers
  //and we can make them const.
  int multiply(const int total, const int b) {
    return total * b;
  }

  //updateTotal doesn't modify b, but it does
  //modify total.
  int updateTotal(int *total, const int b) {
    *total = multiply(*total, b);
  }

  int factorial(int num) {
    int total = 1, b;

    for(b = 1; b <= num; b++) {
      updateTotal(&total, b);
    }

    return total;
  }

Back to Top 

Nested Functions and GNU Autoconf

Applications which use GNU Autoconf, primarily cross-platform UNIX applications, may have accidental usages of nested functions in their configure scripts which are harder to detect. These usages of nested functions may cause configure checks to silently fail, producing an application which builds in an incorrect manner.

If your application uses GNU Autoconf, you should run the configure script after installing Xcode 2.2 and search config.log for the string nested functions are not supported. If you see this string, you have improperly-written configure macros which you should adjust. Problematic macros look like:

    AC_TRY_COMPILE([
        #include <stdio.h>
    ], [
        int main(int argc, char *argv[]) {
            printf("Hello, world!\n");
            return 0;
        }
    ], ...

GNU Autoconf provides its own main function for configure tests, so you should rewrite the macro to look like:

    AC_TRY_COMPILE([
        #include <stdio.h>
    ], [
        printf("Hello, world!\n");
    ], ...

Back to Top 

Linker Support for Nested Functions

The linker provides a switch, -allow_stack_execute, which forces execution of the stack segment to be enabled, even in configurations where it would otherwise default to being disabled. Compilers which understand -fnested-functions will supply -allow_stack_execute to the linker when -fnested-functions is given.

Back to Top 

Document Revision History

DateNotes
2006-01-10This technote explains how to port code which uses nested functions in Xcode 2.2.

Posted: 2006-01-10


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.