Fix UB in utimes and write test
This commit is contained in:
@@ -16,7 +16,6 @@ use crate::{
|
||||
types::{c_char, c_int, c_long},
|
||||
},
|
||||
};
|
||||
use core::ptr::null;
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html>.
|
||||
///
|
||||
@@ -123,11 +122,10 @@ pub unsafe extern "C" fn setitimer(
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn utimes(path: *const c_char, times: *const timeval) -> c_int {
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
// Nullptr is valid here, it means "use current time"
|
||||
let times_spec = if times.is_null() {
|
||||
null()
|
||||
None
|
||||
} else {
|
||||
[
|
||||
Some([
|
||||
timespec {
|
||||
tv_sec: unsafe { (*times.offset(0)).tv_sec },
|
||||
tv_nsec: c_long::from(unsafe { (*times.offset(0)).tv_usec }) * 1000,
|
||||
@@ -136,10 +134,14 @@ pub unsafe extern "C" fn utimes(path: *const c_char, times: *const timeval) -> c
|
||||
tv_sec: unsafe { (*times.offset(1)).tv_sec },
|
||||
tv_nsec: c_long::from(unsafe { (*times.offset(1)).tv_usec }) * 1000,
|
||||
},
|
||||
]
|
||||
.as_ptr()
|
||||
])
|
||||
};
|
||||
unsafe { Sys::utimens(path, times_spec) }
|
||||
let times_ptr = match ×_spec {
|
||||
Some(times_spec) => times_spec.as_ptr(),
|
||||
// Nullptr is valid here, it means "use current time"
|
||||
None => core::ptr::null(),
|
||||
};
|
||||
unsafe { Sys::utimens(path, times_ptr) }
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
@@ -292,6 +292,7 @@ VARIED_NAMES=\
|
||||
sys_socket/getpeername \
|
||||
sys_stat/stat \
|
||||
sys_statvfs/statvfs \
|
||||
sys_time/utimes \
|
||||
sys_utsname/uname \
|
||||
time/gettimeofday \
|
||||
unistd/chdir \
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include "test_helpers.h"
|
||||
|
||||
int main() {
|
||||
const char *test_file = "utimes.txt";
|
||||
struct stat st;
|
||||
struct timeval times[2];
|
||||
|
||||
int fd = open(test_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
ERROR_IF(open, fd, == -1);
|
||||
close(fd);
|
||||
|
||||
times[0].tv_sec = 100;
|
||||
times[0].tv_usec = 0;
|
||||
times[1].tv_sec = 200;
|
||||
times[1].tv_usec = 0;
|
||||
|
||||
int utime_status = utimes(test_file, times);
|
||||
ERROR_IF(utimes, utime_status, == -1);
|
||||
|
||||
int stat_status = stat(test_file, &st);
|
||||
ERROR_IF(stat, stat_status, == -1);
|
||||
|
||||
UNEXP_IF(utimes_atime, st.st_atime, != times[0].tv_sec);
|
||||
UNEXP_IF(utimes_mtime, st.st_mtime, != times[1].tv_sec);
|
||||
|
||||
int unlink_status = unlink(test_file);
|
||||
ERROR_IF(unlink, unlink_status, == -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user