Page allocator returning memory with 170 initialized throughout the block

so here is the code block:

const std = @import("std");

pub fn main() !void {
    const allocator = std.heap.page_allocator;
    const x = try allocator.alloc(u8, 10);
    defer allocator.free(x);
    std.debug.print("Type of x: {}\n", .{@TypeOf(x)});
    const y: [*]u8 = x.ptr;
    std.debug.print("Type of x: {}\n", .{@TypeOf(y)});
    for(0..10) |i|{
        std.debug.print("Type of {d}: {}\n", .{y[i], @TypeOf(y[i])});
    }
}

my intent behind this was to just see what types are being passes around and see how pointers work in zig.
when i ran this using zig run file.zig, i got this:

Type of x: []u8
Type of x: [*]u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
  • first i though the os must have done this then i learnt that modern os zero out the memory before handing it over when a process asks for it via syscall.
  • then i thought the std.heap.page_allocator must have initialized the block of memory with 170 before giving it to x i.e. []u8
  • then i wondered why 170 specifically?
  • then i speculated that maybe the last process which used this memory block must have initialized it to 170 and os didn’t zero it out before giving it to this process.
  • but when i change the size of the block from 10 to 256 and then 512 even then the entire block was initialized to 170, it’s possible that the entire 512 bytes of memory was initialized to 170 but seems very unlikely to me. as i am writing this i realized that to test this hypothesis, i can reboot my pc and see if it still persists so i will do that now and i will post a comment under this post about it

at this point i had reached the end of my knowledge and couldn’t understand what was happening so here i am

please explain what’s happening here

thank you

update after rebooting my pc:

[user@host] misc (main) $ rm -rf ~/.cache/zig/*
[user@host] misc (main) $ zig run file.zig
Type of x: []u8
Type of x: [*]u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
[user@host] misc (main) $ zig build-exe file.zig
[user@host] misc (main) $ ./file
Type of x: []u8
Type of x: [*]u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8
Type of 170: u8

same thing

Welcome to the forum!

What you’re seeing is Zig setting the memory to undefined which is 0xaa (170 decimal) - this makes debugging easier.

Under -O ReleaseFast, this will be optimized out and you’ll see your pages zeroed

6 Likes

170 in hex is aa or in binary 10101010. In debug mode this is the value of undefined, this is so that its easier to spot undefined memory when running the program


to clarify it is the allocator interface writing this value to the memory. In unsafe modes this write will be removed and the memory will be truely undefined

The OS will almost certainly zero the memory out before giving it to the process, but allocators may reuse the memory so allocations won’t always get zeroed memory.

5 Likes

thanks for the clarification that really helped me understand this deeper