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

Abierto Apto para principiantes
#5,697 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
76/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
rust

Línea de trabajo

Lee src/unix/linux_like/linux/gnu/b32/mod.rs y la configuración del destino en build.rs descrita en la issue. Compara los diseños de timex con bits/timex.h de glibc para riscv32; después, comprueba el diseño de riscv32 y asegúrate de que i686 y armv7 conservan sus tamaños actuales. El objetivo se cumple cuando timex coincide con el diseño de 208 bytes de glibc en riscv32 sin escribir más allá de su final.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
Rust
Estrellas
2.6k
Forks
1.3k
Merge medio
2 d 8 h
PR fusionados (30 d)
27

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de rust-lang/libc

Todos los issues de rust-lang/libc

Issues similares

Más issues de Rust

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.