Skip to content

introduce runtime safety for dangling stack pointers #23528

@andrewrk

Description

@andrewrk

I didn't see anywhere this was clearly written up so here it is.

It's not possible to catch use-after-free of stack memory at compile-time (#5725) because it can be equated to the halting problem. I'll leave that proof as an exercise for the reader.

So, we catch it at runtime, in safe build modes.

Step 1, do escape analysis. Only stack locals which have pointers captured which might outlive their scope are subject to these safety checks.

Step 2, introduce an API for heap-allocating memory, like this:

extern fn safe_alloc(size: usize, alignment: u8) ?[*]u8;
extern fn safe_free(ptr: [*]u8, size: usize, alignment: u8, rbp: usize) void;

These would default to using a slimmed down version of std.heap.DebugAllocator - one that avoids reuse of memory addresses, but does not capture stack traces. Perhaps this would be implemented in compiler_rt so that it could be optimized and be compiled without these safety checks, which would otherwise be recursive.

The subset of stack values which have possibly escaped pointers would then be allocated this way. As an optimization, if there were multiple escaped values in the stack frame, they could be allocated together and freed together.

The allocation function could fail, so the stack slots would still be reserved for such case. Stack base address is passed to safe_free so that it can ignore such fallback pointers.

Heap-allocating instead of stack-allocating is obviously significantly slower, so that's why it's important for Step 1 to work well, in order to make Step 2 rare.

So then, when a dangling stack pointer is used, it either segfaults, or its bytes have been memset to the 0xaa pattern, making it very likely to immediately trigger a crash. Even if it does not trigger a crash, however, it is still memory safe in the sense that the memory does not alias any other allocations, making it easier to debug in Debug mode, and avoiding a certain class of bugs in ReleaseSafe mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedThis proposal is planned.enhancementSolving this issue will likely involve adding new logic or components to the codebase.proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions