libc: Problem in implementing siginfo_t for Linux

The definition of siginfo_t in Linux (https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h) uses a inlined union type as its last field. Rust did not have support for union types, I guess that was why those fields were left as a padding array in current libc implementation.

I made some attempts to use union (introduced in Rust 1.19) to represent siginfo_t. However the resulting struct is 8 bytes larger than the original one (the one currently in libc, which is the same size as the C struct type). See the code here: https://play.rust-lang.org/?gist=99630206fcc8fd44b452d22552b37793&version=stable

My guess is the 8 more bytes come from two places:

  1. the union type is 8 bytes aligned, but the first 3 fields of siginfo_t are 12 bytes (3x 4-bytes integer), so the padding is needed after the first 3 fields, which makes the offset of the union type at 16 bytes (instead of 12 bytes)
  2. because the union type is 8 bytes aligned, so the size of the union type cannot be 4*29 (which is not a multiple of the 8 bytes alignment), thus padding is needed at the end to make it a muliple of 8.

I am not sure why the C definition does not have issues like this (probably because it uses inlined union in the struct definition) and how to properly implement siginfo_t in Rust. Please correct me if I am wrong. For my project, I have to extract data from the padding array (which looks awful).

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 3
  • Comments: 19 (16 by maintainers)

Commits related to this issue

Most upvoted comments

@qinsoon Marking the si_fields_t union as #[repr(C, packed)] instead of just #[repr(C)] makes it the same size as the original one. Is this correct / does this help?