riscv32gc-unknown-linux-gnu: `timex` uses the 32-bit `c_long` layout (144 bytes), glibc's riscv32 `struct timex` is 208 bytes

オープン 初心者向け
#5,697 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@compiler-segfault がすでに取り組んでいます。

2026年11月5日 から。

  • #5717 @compiler-segfault による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust

調査の方向性

src/unix/linux_like/linux/gnu/b32/mod.rsと、issueで説明されているbuild.rsのターゲット設定を読みます。riscv32向けのglibcのbits/timex.hとtimexのレイアウトを比較し、その後、riscv32のレイアウトを確認して、i686とarmv7が現在のサイズを維持していることを確かめます。timexがriscv32でglibcの208バイトのレイアウトと一致し、末尾を越えて書き込まない状態になれば完了です。

索引モデルが issue の本文から書いたものです。

説明

C-bug

Target: riscv32gc-unknown-linux-gnu (glibc; 64-bit time_t is this target's only ABI)

Versions: libc 0.2.186, 0.2.191 and 1.0.0-alpha.5 (the declarations quoted below are unchanged on main); glibc 2.44; rustc 1.98.1.

src/unix/linux_like/linux/gnu/b32/mod.rs declares timex twice: the c_longlong layout under #[cfg(gnu_time_bits64)] (0.2.191 lines 191-227) and the c_long layout under #[cfg(not(gnu_time_bits64))] (lines 229-262). The build script never sets gnu_time_bits64 on riscv32, because its time_t is 64-bit already (build.rs:329-345):

    // 32-bit arches with 64-bit time_t by default. rv32 is 64-only, `x86_64` covers the x32 arch,
    // `!(linux|windows|hurd)` covers vxworks and future platforms.
    let gnu32_already_time64 = target_arch == "riscv32"
        || target_arch == "x86_64"
        || !matches!(target_os.as_str(), "linux" | "windows" | "hurd");
    let gnu = target_env == "gnu";
    let gnu32_time64 = gnu && target_ptr_width == "32" && (gnu32_timebits == "64" || time64);

    if gnu32_time64 && !gnu32_already_time64 {

so riscv32 gets the time32 layout, with 32-bit long fields:

    #[cfg(not(gnu_time_bits64))]
    pub struct timex {
        pub modes: c_uint,
        pub offset: c_long,
        pub freq: c_long,
        pub maxerror: c_long,
        pub esterror: c_long,
        pub status: c_int,
        pub constant: c_long,
        pub precision: c_long,
        pub tolerance: c_long,
        pub time: crate::timeval,
        ...

glibc's riscv32 struct timex takes the long long layout whenever __TIMESIZE == 64 && __WORDSIZE == 32 (glibc 2.44, bits/timex.h:26-36; riscv32's bits/timesize.h defines __TIMESIZE as 64):

struct timex
{
# if defined __USE_TIME64_REDIRECTS || (__TIMESIZE == 64 && __WORDSIZE == 32)
  unsigned int modes;          /* mode selector */
  int :32;                     /* pad */
  long long offset;            /* time offset (usec) */
  long long freq;              /* frequency offset (scaled ppm) */
  long long maxerror;          /* maximum error (usec) */
  long long esterror;          /* estimated error (usec) */
  int status;                  /* clock command/status */
  int :32;                     /* pad */

Layouts, measured

libc timex glibc struct timex
size 144 208
offset of freq 8 16
offset of status 20 40
offset of time 40 72
offset of tai 92 160

The libc column: const assertions under cargo check --target riscv32gc-unknown-linux-gnu, the same on 0.2.186, 0.2.191 and 1.0.0-alpha.5. The glibc column: _Static_asserts compiled by riscv32-unknown-linux-gnu-gcc 16.2.1 against glibc 2.44's headers.

At run time (qemu-riscv32 10.2.3, glibc 2.44, libc 0.2.191): adjtimex() with modes = 0, called on a libc::timex at the head of a canary-filled 256-byte buffer, changes the 20 bytes at offsets 144-163 (glibc's errcnt, stbcnt and tai): it writes past the end of the Rust struct. And status reads 0x0 (the upper half of glibc's freq) while glibc's status holds 0x40, STA_UNSYNC, so an unsynchronized clock reads as synchronized.

Minimal example (no dependency but libc):

#![no_std]
const _: [(); 208] = [(); core::mem::size_of::<libc::timex>()];

cargo check --target riscv32gc-unknown-linux-gnu fails with expected an array with a size of 208, found one with a size of 144.

A possible fix: give riscv32 the c_longlong layout too, #[cfg(any(gnu_time_bits64, target_arch = "riscv32"))] on the first declaration and #[cfg(not(any(gnu_time_bits64, target_arch = "riscv32")))] on the second. With that change on 0.2.191: riscv32 208 bytes, adjtimex() changes nothing past the struct, status reads 0x40; i686 and armv7 keep their 128 bytes.

Related: the time64 tracking issue #5507.

主要言語
Rust
スター
2.6k
フォーク
1.3k
平均マージ
2日 8時間
マージ済み PR(30日)
27

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rust-lang/libc のほかの issue

rust-lang/libc の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。