Freeing the Linux Auxiliary Vector

Status quo

When you launch a Linux program, it inherits a full copy of the entire environment, arguments, and various other things into its memory, for its entire life. This is typically a 4K page, and on the particularly bad Ubuntu more like two pages. Type this into a terminal to see the size of the environment portion.

env | wc -c

ARGV[0]is in there twice (AT_EXECFN which the caller cannot modify, and ARGV[0] which the caller can specify, and whose value is only customary), for the entire life-time of the every program. The aux vector can be giant, and this is completely out of the application's control. The minimum upper-bound is 128KiB, and since Linux 2.6.23 is raised to 1/4 of the stack size. This means that to avoid undefined stack overflow your program has to calculate that it can only use 3/4 of the stack!


    const bootstrap = @import("std").bootstrap;
    pub fn init() void {
        // parse arguments, environment, and auxilery vector,
        // putting anything needed into global variables[1]
    bootstrap.init = init; // This enables the feature.
    pub fn main() void {
        // The frame pointer is guaranteed to point to the edge
        // of the stack's memory


  • Less memory usage.
  • Predictable memory usage: main's stack is always at the edge of the allocation
  • Separates parsing of user input from the logic of the program (think Model-View-Controller)
  • No need to assure use of only 3/4 of stack
  • Actually (with the rest of Zig) possible to write an application that can gracefully handle out-of-memory conditions

[1] Global variables are namespaced in Zig, and while they need to be used carefully in shared libraries, the do not have the same problems as global variables in C.