Description: SharedMem::stat: use the PowerPC offsets of struct shmid_ds The per-OS offset table assumes the asm-generic field order, where shm_segsz follows ipc64_perm and the three time fields come after it. PowerPC puts the time fields first and shm_segsz after them, so segsz, atime, dtime and ctime are all read from the wrong place there. cpid, lpid and nattch are unaffected: both layouts are 48 bytes of ipc64_perm followed by four 8-byte fields, so those three keep their offsets. . Companion to powerpc-shmid_ds-offset.patch, which does the same for shm_segments(). No test currently catches this one: t/05-shm_stat.t asserts only segsz >= SHM_BUFSIZ, and the value misread on PowerPC is shm_atime, a timestamp far larger than SHM_BUFSIZ. The suite therefore passes without this patch, but stat() still reports nonsense on ppc64el and ppc64. . The 64-bit offsets match the kernel headers and qemu's target_structs.h, and are confirmed by a passing test suite on ppc64el under emulation. The 32-bit PowerPC arm is derived from the headers only and is untested; Debian's 32-bit powerpc is a ports architecture with no buildd coverage. Author: Edmund Lodewijks Forwarded: https://github.com/stevieb9/ipc-shareable/issues/66 Last-Update: 2026-09-02 diff --git a/lib/IPC/Shareable/SharedMem.pm b/lib/IPC/Shareable/SharedMem.pm index 4e6529e..3388ef4 100644 --- a/lib/IPC/Shareable/SharedMem.pm +++ b/lib/IPC/Shareable/SharedMem.pm @@ -191,14 +191,28 @@ sub stat { my %values; if ($^O eq 'linux') { + # PowerPC orders struct shmid_ds with the three time fields before + # shm_segsz; every other Linux architecture puts shm_segsz first, + # straight after ipc64_perm. Only that part of the struct differs. + my $ppc = $Config{archname} =~ /^(?:powerpc|ppc)/i; + if ($Config{longsize} == 8) { # 64-bit Linux: ipc64_perm is 48 bytes. # ipc64_perm: key(4) uid(4) gid(4) cuid(4) cgid(4) mode(4) # seq(2) pad2(2) [4-byte align-pad] unused1(8) unused2(8) # shmid_ds: segsz(8) atime(8) dtime(8) ctime(8) cpid(4) lpid(4) nattch(8) + # PowerPC: atime(8) dtime(8) ctime(8) segsz(8) cpid(4) lpid(4) nattch(8) + # (PowerPC's ipc64_perm is also 48 bytes: mode(4) seq(4) pad1(4) + # where the generic one has mode(4) seq(2) pad2(2) plus padding.) - @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)} - = unpack('x[4] L L L L L x[24] Q q q q l l Q', $data); + if ($ppc) { + @values{qw(uid gid cuid cgid mode atime dtime ctime segsz cpid lpid nattch)} + = unpack('x[4] L L L L L x[24] q q q Q l l Q', $data); + } + else { + @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)} + = unpack('x[4] L L L L L x[24] Q q q q l l Q', $data); + } } else { # 32-bit Linux: ipc64_perm is 36 bytes (unsigned long = 4 bytes). @@ -207,8 +221,18 @@ sub stat { # shmid_ds: segsz(4) atime(4) atime_nsec(4) dtime(4) dtime_nsec(4) # ctime(4) ctime_nsec(4) cpid(4) lpid(4) nattch(4) - @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)} - = unpack('x[4] L L L L L x[12] L L x[4] L x[4] L x[4] l l L', $data); + # PowerPC 32-bit differs again: ipc64_perm is 48 bytes there, and + # each time field is preceded by its _high half, with one more + # pad word before segsz. + + if ($ppc) { + @values{qw(uid gid cuid cgid mode atime dtime ctime segsz cpid lpid nattch)} + = unpack('x[4] L L L L L x[24] x[4] L x[4] L x[4] L x[4] L l l L', $data); + } + else { + @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)} + = unpack('x[4] L L L L L x[12] L L x[4] L x[4] L x[4] l l L', $data); + } } } elsif ($^O eq 'freebsd' && $Config{longsize} == 8) {