Skip to content

time_t is the wrong size on 32bit linux #4307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
WhyNotHugo opened this issue Mar 7, 2025 · 3 comments
Closed

time_t is the wrong size on 32bit linux #4307

WhyNotHugo opened this issue Mar 7, 2025 · 3 comments
Labels
C-bug Category: bug

Comments

@WhyNotHugo
Copy link

WhyNotHugo commented Mar 7, 2025

On almost all 32bit platforms, this crate defines time_t = i32: https://docs.rs/libc/0.2.170/src/libc/unix/linux_like/linux/gnu/b64/mod.rs.html#19

At least on Linux/musl, libc defines time_t = i64: https://git.musl-libc.org/cgit/musl/tree/include/alltypes.h.in#n12

See also: https://musl.libc.org/time64.html

Examples

The following sample compiles in 64bit but does not compile on 32bit:

fn main() {
    let tv_sec: i64 = 1741340955;
    let mut tm = unsafe { std::mem::zeroed() };

    if unsafe { libc::localtime_r(&tv_sec, &mut tm) }.is_null() {
        panic!("Failed to determine local time via localtime_r");
    }

    println!(
        "Today is {}-{:02}-{:02}",
        tm.tm_year + 1900,
        tm.tm_mon + 1,
        tm.tm_mday
    );
}

The equivalent C code, compiles and produces the correct result on both 64bit and 32bit:

int main() {
    int64_t tv_sec = 1741340955;
    struct tm tm;

    if (localtime_r(&tv_sec, &tm) == NULL) {
        perror("Failed to determine local time via localtime_r");
        exit(EXIT_FAILURE);
    }

    printf("Today is %d-%02d-%02d\n",
           tm.tm_year + 1900,
           tm.tm_mon + 1,
           tm.tm_mday);

    return 0;
}

Context

This becomes a problem when using other crates which interact with the same underlying type from libc (the implementation itself, not the libc crate).

The following works fine on 64bit:

    let Timespec { tv_sec, tv_nsec } = rustix::clock_gettime(ClockId::Realtime);

    // SAFETY: This is safe as long as tm is fully overwritten before use, which localtime_r does.
    let mut tm = unsafe { std::mem::zeroed() };
    // SAFETY: localtime_r is called with a valid pointer to secs and a mutable reference to tm.
    if unsafe { localtime_r(&tv_sec, &mut tm) }.is_null() {
        bail!("Failed to determine local time via localtime_r");
    }

But on 32bit platforms it fails with:

error[E0308]: mismatched types
    --> src/paths.rs:44:29
     |
44   |     if unsafe { localtime_r(&tv_sec, &mut tm) }.is_null() {
     |                 ----------- ^^^^^^^ expected `*const i32`, found `&i64`
     |                 |
     |                 arguments to this function are incorrect
     |
     = note: expected raw pointer `*const i32`
                  found reference `&i64`
note: function defined here
    --> /home/buildozer/.cargo/registry/src/index.crates.io-1cd66030c949c28d/libc-0.2.170/src/unix/mod.rs:1328:12
     |
1328 |     pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm;
     |            ^^^^^^^^^^^
@WhyNotHugo WhyNotHugo added the C-bug Category: bug label Mar 7, 2025
@ChrisDenton
Copy link
Member

see also #3248 #1848

@tgross35
Copy link
Contributor

tgross35 commented Mar 7, 2025

Yeah, the issues Chris linked cover this thoroughly so I'm going to close this. See also relevant PRs #3175, #3791 and #3068, these need some help moving forward if that is something you are interested in.

@WhyNotHugo
Copy link
Author

WhyNotHugo commented Mar 7, 2025

Thanks, I'm following up on these. Note that #3175 is about a different libc implementation, where I believe that the size of time_t is configurable at build time, whereas musl has a fixed size.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: bug
Projects
None yet
Development

No branches or pull requests

3 participants