Do I need to fill all the fields of an `extern struct`?

I’m trying to use the sysinfo syscall on Linux to get the total ram and free ram. The sysinfo struct on Linux looks like this:

struct sysinfo {
    long uptime;
    unsigned long loads[3];
    unsigned long totalram;
    unsigned long freeram;
    unsigned long sharedram;
    unsigned long totalswap;
    unsigned long freeswap;
    unsigned short procs;
    unsigned long totalhigh;
    unsigned long freehigh;
    unsigned int mem_unit;
    char _f[20-2*sizeof(long)-sizeof(int)];
};

I created an extern struct to match this layout. However, I realized that I don’t need to define all the fields, I can define the fields up to and including the field I want and would still get the expected result. Here’s my code:

const std = @import("std");

const linux = std.os.linux;

const sysinfo = extern struct {
    uptime: c_long,
    loads: [3]c_ulong,
    totalram: c_ulong,
    freeram: c_ulong,
};

pub fn main() void {
    var _sysinfo: sysinfo = undefined;
    if (linux.syscall1(.sysinfo, @intFromPtr(&_sysinfo)) != 0) {
        std.process.exit(1);
    }

    const total_bytes: f32 = @floatFromInt(sysinfo.totalram);
    const free_bytes: f32 = @floatFromInt(sysinfo.freeram);

    // ...
}

Is what I did here fine or should I define all the fields of the struct to match the C structure?

It is not fine. You must define all the fields.

The syscall writes to all the expected fields even if they are not present. The result of using a _sysinfo that have less size than it must is memory corruption and undefined behavior.

5 Likes