Skip to content
Tech News
← Back to articles

Using GCC's Nested Functions with Wide Pointers and No Trampolines II

read original more articles
Why This Matters

The article highlights advancements in GCC 16 that improve security and efficiency when using nested functions. By ensuring that nested functions without variable capture do not require run-time trampolines, it reduces security risks associated with executable stacks and optimizes performance, benefiting both developers and end-users in the tech industry.

Key Takeaways

Using GCC's Nested Functions with Wide Pointers and no Trampolines II

Martin Uecker, 2026-07-14

Introduction

When the address of a nested function is taken, GCC creates at trampoline at run-time. This trampoline is placed on the stack, which means that the stack has to be executable. This is problematic because a non-executable stack is an important security feature. For some time now, GCC has the option to place the trampoline on the heap, which is better but still not ideal as the allocation has a higher cost and the trampoline could leak when longjmp is used.

Previously, I pointed out how this could be avoided with a new wide pointer type, and also talked about a preliminary patch to GCC that implements some core functionality that would be necessary for this.

Here, I want to give two updates.

GCC 16: Nested Functions Without Capture

First, GCC 16 was released. In GCC 16 it is guaranteed that a nested function that does not access variables of a parent function will not require a trampoline. In practice, this was already ensured when optimizing, but now it is also ensured when not optimizing and documented. This also means that you can safely return such a function from its parent and that you will get a warning when trying to return a function that does access the local context (at least in simple cases where this is obvious to the compiler) as in the following example (Godbolt Example)

typedef int cb_f(int); cb_f *foo(int x) { int worker(int y) { return x + y; // capture } return worker; } cb_f *bar(int _x) { static int x; x = _x; int worker(int y) { return x + y; // no capture } return worker; }

... continue reading