# Protecting against buffer overflows

**URL:** <https://ziggit.dev/t/protecting-against-buffer-overflows/15530>\
**Category:** Brainstorming\
**Tags:** memory-management\
**Created:** [May 15, 2026, 3:52am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530 "2026-05-15T03:52:12Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![legenduzo](https://ziggit.dev/user_avatar/ziggit.dev/legenduzo/32/8009_2.png) [@legenduzo](https://ziggit.dev/u/legenduzo)\
**Post date:** [May 15, 2026, 3:52am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/1 "2026-05-15T03:52:12Z")

</div>

As I create more and more buffers in my life, and I see all the CVEs caused by buffer overflows, I’ve been growing towards this pattern of working with buffers in Zig:

```zig
const buf: [512]u8,
const buf_len: u9,

// 1. An overflow guard
if (buf.len < input.len) {
    @branchHint(.unlikely);
    return error.BufferOverflow;
}
@memcpy(buf[buf_len..input.len], input);
// 2. A post length check by buf_len
buf_len += input.len;

```

Notice that `maxInt(u9) == 511`.  
To me, if an input will be exactly 512 bytes for a 512-sized buffer, then it’s quite literally looking for trouble.

Also, I don’t use `assert()` because you never know what’s going to run in ReleaseFast. But I also want to give the compiler all the information I can so it can optimize as much as possible, hence the `@branchHint`.

I believe this pattern is significantly cheaper than Address Sanitization used in large programs (like Chrome) and enforced by the kernel through KASAN.

How am I not a genius with this? (no, really, poke holes in my bubble 🙂).

---

<div class="post-metadata">

**Author:** ![Cloudef](https://ziggit.dev/user_avatar/ziggit.dev/cloudef/32/1370_2.png) [@Cloudef](https://ziggit.dev/u/Cloudef)\
**Post date:** [May 15, 2026, 5:13am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/2 "2026-05-15T05:13:07Z")

</div>

I think that branchHint is not neccessary as error paths should already be marked cold.  
Imo here you prob should use writer instead. `@memcpy` is for scenarios where you know you can’t overflow.

```rs
var writer: std.Io.Writer = .fixed(&buf);
try writer.writeAll(input); // errors if overflow

```

Other option is to compile with `ReleaseSafe` and selectively set hot paths `@setRuntimeSafety(false)`, but this of course makes just overflows panics.

---

<div class="post-metadata">

**Author:** ![jmctagger](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/8dc957/32.png) [@jmctagger](https://ziggit.dev/u/jmctagger)\
**Post date:** [May 15, 2026, 5:17am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/3 "2026-05-15T05:17:39Z")

</div>

Am I missing something? Can you clarify input? Can `input.len` be less than `buf_len`? The `memcpy` is confusing me.

Also, would most consider fuzz testing in debug with something like `if (a < b) unreachable` fairly robust? Maybe not for the space station? Otherwise, `@branchHint` seems valuable.

EDIT: I didn’t realize that “error paths should already be marked cold” - thanks @Cloudef

---

<div class="post-metadata">

**Author:** ![legenduzo](https://ziggit.dev/user_avatar/ziggit.dev/legenduzo/32/8009_2.png) [@legenduzo](https://ziggit.dev/u/legenduzo)\
**Post date:** [May 16, 2026, 1:16am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/4 "2026-05-16T01:16:33Z")

</div>

Using .fixed definitely looks neater and more concise.

Thanks.

Why isn’t .fixed also better for cases where you can’t overflow?

---

<div class="post-metadata">

**Author:** ![Cloudef](https://ziggit.dev/user_avatar/ziggit.dev/cloudef/32/1370_2.png) [@Cloudef](https://ziggit.dev/u/Cloudef)\
**Post date:** [May 16, 2026, 3:22am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/5 "2026-05-16T03:22:36Z")

</div>

It may produce more code in the binary (havent checked though 🙂 )

---

<div class="post-metadata">

**Author:** ![LucasSantos91](https://ziggit.dev/user_avatar/ziggit.dev/lucassantos91/32/440_2.png) [@LucasSantos91](https://ziggit.dev/u/LucasSantos91)\
**Post date:** [May 16, 2026, 3:44am UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/6 "2026-05-16T03:44:43Z")

</div>

Your pattern is the late BoundedArray.  
+1 for the team “Resurrect BoundedArray”.

> [@legenduzo](#):
>
> To me, if an input will be exactly 512 bytes for a 512-sized buffer, then it’s quite literally looking for trouble.

To me, it looks like optimal usage of resources. Code appropriately (like by wrapping the unsafe code in a well-tested BoundedArray), and that won’t be a problem. You can add some extra bytes as “guard rails” in a debug build, set them to some sentinel, and check if they still hold their sentinel value later. Paranoia is debug builds. If you don’t trust your code enough to set it to release mode, that’s good sign it’s not ready for release.

---

<div class="post-metadata">

**Author:** ![floooh](https://ziggit.dev/user_avatar/ziggit.dev/floooh/32/2989_2.png) [@floooh](https://ziggit.dev/u/floooh)\
**Post date:** [May 16, 2026, 2:32pm UTC](https://ziggit.dev/t/protecting-against-buffer-overflows/15530/7 "2026-05-16T14:32:09Z")

</div>

Isn’t that what ReleaseSafe mode is for? E.g. builtin range checks without requiring manual intervention? E.g. since Zig has added all those additional semantics over C (slices and arrays carrying their length) to enable to automatic runtime checks. Why do the same thing manually again (like in C code) when the compiler automatically injects range checks anyway? Of course Zig will panic, but that’s the right thing to do for an ‘unintended’ buffer overflow.

For any ‘serious’ Zig applications I would also never consider to distribute them compiled in ReleaseFast mode, but only in ReleaseSafe mode (ReleaseFast should really be called ReleaseUnsafe, and ReleasSafe should just be called Release IMHO).

Instead of returning a soft error which then needs to be handled by the caller (how even? try with less and less data in a loop until the error goes away?) - I would instead add a function which returns the available buffer space, so that the caller can partition the data correctly without running into an unintended buffer overflow.
