Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

19 years as a C/C++/ObjC developer, and this never occurred to me.

And it works with C Blocks!

    typedef int IntegerProcessor(int);

    int executeTheFunctionPointer(IntegerProcessor* function)
    {
        return function(23);
    }

    int executeTheBlock(IntegerProcessor^ block)
    {
        return block(32);
    }

    int doubler(int a)
    {
        return a * 2;
    }

    int main(int argc, const char * argv[])
    {
        IntegerProcessor* myFunctionPtr = &doubler;

        int a = executeTheFunctionPointer(myFunctionPtr);
        printf("%d\n", a); // 46

        IntegerProcessor^ myBlock = ^(int b) {
            return a * b;
        };

        a = executeTheBlock(myBlock);
        printf("%d\n", a); // 1472

        return 0;
    }
My mind is completely blown.


This is so cool. Where can I find documentation on the following?

   IntegerProcessor^ myBlock = ^(int b) {
      return a * b;
   };

I wasn't aware C supported nested functions.


There's a GNU extension for it.

https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

But it's not a proper closure, and it's not GC'd, so it's pretty useless.


Last time I checked, Clang doesn't support nested functions although it supports most of GNU extensions (or similar features with slightly altered syntax).

I'm not 100% sure what you mean by "proper closure" but it does capture variables from the outer scope. It has limitations with scopes and lifetimes, of course.


Proper closures require "fat pointers", basically you're storing two pointers, one to the function and one to its context data. (In the case of a nested function that's its stackframe.) They also require that stackframes be generally allocated on the heap.

C doesn't have a type for that, it only has function pointers, which only have space for a single pointer. So what GCC does is actually a horrible hack - it dynamically creates a function (called a trampoline), which calls the actual function with a pointer to its data. But because GCC doesn't have true closures, and only refers to the surrounding function's existing stackframe, which is on the stack, not the heap, this only works until the surrounding function has returned. And since the trampoline is also allocated on the stack, this requires the stack to be executable, which is Not Great for security.


Yes, it's a bit ugly but it still doesn't make it useless. It could be useful for e.g. passing a comparator to qsort using a captured variable to pass the comparison criteria (e.g. compare arrays according to the n'th element).

> So what GCC does is actually a horrible hack - it dynamically creates a function (called a trampoline), which calls the actual function with a pointer to its data.

Well you can call it a horrible hack but it's pretty clever. There's no other way to do this without having a rich runtime system and a language with a built-in concept of a heap (and perhaps a garbage collector).

> And since the trampoline is also allocated on the stack, this requires the stack to be executable, which is Not Great for security.

Yeah - this is pretty nasty. Executable stack is less than useful, although it's not enough to protect against stack/buffer overflow exploits that utilize ROP or other advanced attack methods.

However - in my practical experiments, I have noticed that the optimizer will get rid of most trivial trampolines if the resulting function pointer isn't stored or passed to a function in a foreign translation unit. LLVM in particular is really good in eliminating trampolines.

I wish there was a way to have compile time certainty that no trampolines ever get emitted on the stack. You could still use capturing nested functions with certain limitations.

But yeah - it's not the most useful feature, primarily because it's GCC only and secondarily because, at worst, you'll end up executing a few bytes of machine code from the stack.



So is mine.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: