Zaman - Comptime lifetime annotations for Zig

Zaman


Zaman (زمان in Persian) is a memory safety tool for Zig that tries to prevent use-after-free and ifetime confusion at compile time by encoding arena lifetimes directly into pointer types.

Why does this exist?

I have several die-hard Rustacean friends who were constantly bragging about their nice memory-safety features, so I decided to end the discussion by implementing their beloved lifetimes using Zig’s comptime

Why should you care?

  • Manual memory management in Zig is manageable - but sometimes you need stronger guarantees
  • There are safe usage patterns that are not implementable in Rust
  • Usually the attack surface is limited compared to the entire codebase, so you don’t need to bear the burden of Rust’s rules for its entirety
  • For long-running applications, Zaman might reduce memory fragmentation and improve allocation throughput at the cost of slightly higher memory consumption, compared to many allocation strategies including Rust’s (you can optimize this balance as you wish)
  • This is a benchmark of what Zig’s comptime is capable of and you might apply these ideas to your own use-cases

Usage

const La = Lifetime(@src(), .{});
defer La.deinit();

const x = try La.create(i32);
var y = try La.create(i32);

// x and y share the Lifetime La

const Lb = Lifetime(@src(), .{});
defer Lb.deinit();

const z = try Lb.create(i32);
y = z; // compilation error!
// z has the Lifetime Lb != La

What about use-after-free?

const La = Lifetime(@src(), .{});
defer La.deinit();

var use_after_free: La.Bound(*u32) = undefined;
{
    const Lb = Lifetime(@src(), .{});
    defer Lb.deinit();

    const x = try Lb.create(u32);
    x.set(10);
    use_after_free = x;
}
std.debug.print("{}\n", use_after_free.get());

compilation output

src/uaf.zig:14:26: error: expected type 'lifetime.Bounded(*u32,"uaf |zaman> uaf.zig:4:25"[0..24])',
                                  found 'lifetime.Bounded(*u32,"uaf |zaman> uaf.zig:9:29"[0..24])'
        use_after_free = x;
                         ^
src/lifetime.zig:84:12: note: struct declared here (2 times)
    return struct {
           ^~~~~~

Supported Zig versions

This package doesn’t use any version specific std/language feature so it could be used in any zig version with zero or minimal modification

  • master directly supports from zig-0.15.0 to zig-0.16.0
6 Likes