Skip to content

libc's struct Stat is defined incorrectly on 64-bit FreeBSD #25155

Closed
@aidancully

Description

@aidancully

blksize_t on 64-bit FreeBSD is 32 bits, not 64.

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stddef.h>

#define pr_field_offset(field) \
  do { printf(# field ": %d\n", offsetof(struct stat, field)); } while (0)

int main(int argc, char *argv[])
{
  printf("%d\n", sizeof(struct stat));
  pr_field_offset(st_dev);
  pr_field_offset(st_size);
  pr_field_offset(st_blocks);
  pr_field_offset(st_blksize);
  pr_field_offset(st_flags);
  pr_field_offset(st_gen);
  pr_field_offset(st_birthtim);
  return 0;
}

on FreeBSD x86_64 yields:

120
st_dev: 0
st_size: 72
st_blocks: 80
st_blksize: 88
st_flags: 92
st_gen: 96
st_birthtim: 104
#![feature(libc)]
extern crate libc;

macro_rules! containerof_field_offset {
    ($container:ty : $field:ident) => (unsafe {
        &(*(0usize as *const $container)).$field as *const _ as usize
    })
}
macro_rules! pr_field_offsets {
  ( $( $field:ident ),* ) => (unsafe {
    $(
      println!("{}: {}", stringify!($field), containerof_field_offset!(libc::stat : $field));
    )*
  })
}

fn main() {
  println!("{}", std::mem::size_of::<libc::stat>());
  pr_field_offsets!(st_dev, st_ino, st_mode, st_nlink, st_uid, st_gid, st_rdev, st_atime, st_atime_nsec);
  pr_field_offsets!(st_atime, st_atime_nsec, st_mtime, st_mtime_nsec, st_ctime, st_ctime_nsec);
  pr_field_offsets!(st_size, st_blocks, st_blksize, st_flags, st_gen, st_lspare, st_birthtime, st_birthtime_nsec);
  pr_field_offsets!(__unused);
}

yields:

$ ./test
136
st_dev: 0
st_ino: 4
st_mode: 8
st_nlink: 10
st_uid: 12
st_gid: 16
st_rdev: 20
st_atime: 24
st_atime_nsec: 32
st_atime: 24
st_atime_nsec: 32
st_mtime: 40
st_mtime_nsec: 48
st_ctime: 56
st_ctime_nsec: 64
st_size: 72
st_blocks: 80
st_blksize: 88
st_flags: 96
st_gen: 100
st_lspare: 104
st_birthtime: 112
st_birthtime_nsec: 120
__unused: 128

I tracked this down to the blksize_t type definition, which is unconditionally 32-bit on FreeBSD (see here, noting this line:

typedef __uint32_t      __blksize_t;    /* file block size */

this is unconditionally the definition of __blksize_t on FreeBSD - whether on 32-bit or 64-bit platform.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions