Skip to content

Commit 3eaeae0

Browse files
authored
Add safe rules for time (#260)
This also adds a new dependency called jiff. jiff is used to avoid manually implementing strftime and localtime_r In general, nix only contains safe wrappers over syscalls. Everything which is a pure library implementation is not included
1 parent b33bdc3 commit 3eaeae0

12 files changed

Lines changed: 664 additions & 1 deletion

File tree

‎libc-dep/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ edition = "2024"
66
[dependencies]
77
libc = "0.2"
88
nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] }
9+
jiff = "0.2"

‎libcc2rs/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ edition = "2024"
77
libcc2rs-macros = { path = "../libcc2rs-macros", version = "0.1.0" }
88
libc = "0.2"
99
nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] }
10+
jiff = "0.2"

‎libcc2rs/src/libc_shims/time.rs‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,40 @@ pub struct Tm {
2020
pub tm_zone: Value<Ptr<u8>>,
2121
}
2222

23+
impl Tm {
24+
pub fn from_zoned(dt: &jiff::Zoned) -> Self {
25+
let tm = Tm::default();
26+
*tm.tm_sec.borrow_mut() = dt.second() as i32;
27+
*tm.tm_min.borrow_mut() = dt.minute() as i32;
28+
*tm.tm_hour.borrow_mut() = dt.hour() as i32;
29+
*tm.tm_mday.borrow_mut() = dt.day() as i32;
30+
*tm.tm_mon.borrow_mut() = dt.month() as i32 - 1;
31+
*tm.tm_year.borrow_mut() = dt.year() as i32 - 1900;
32+
*tm.tm_wday.borrow_mut() = dt.weekday().to_sunday_zero_offset() as i32;
33+
*tm.tm_yday.borrow_mut() = dt.day_of_year() as i32 - 1;
34+
*tm.tm_isdst.borrow_mut() = 0;
35+
*tm.tm_gmtoff.borrow_mut() = dt.offset().seconds() as i64;
36+
#[cfg(target_os = "linux")]
37+
let zone: &'static [u8] = b"GMT";
38+
#[cfg(target_os = "macos")]
39+
let zone: &'static [u8] = b"UTC";
40+
*tm.tm_zone.borrow_mut() = Ptr::from_string_literal(zone);
41+
tm
42+
}
43+
44+
pub fn to_civil(&self) -> Result<jiff::civil::DateTime, jiff::Error> {
45+
jiff::civil::DateTime::new(
46+
(*self.tm_year.borrow() + 1900) as i16,
47+
(*self.tm_mon.borrow() + 1) as i8,
48+
*self.tm_mday.borrow() as i8,
49+
*self.tm_hour.borrow() as i8,
50+
*self.tm_min.borrow() as i8,
51+
*self.tm_sec.borrow() as i8,
52+
0,
53+
)
54+
}
55+
}
56+
2357
impl Clone for Tm {
2458
fn clone(&self) -> Self {
2559
Self {

‎rule-preprocessor/src/semantic.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,14 @@ fn build_rustc_args(crate_root: &Path) -> Vec<String> {
4646
args.push("-L".to_string());
4747
args.push(format!("dependency={}", deps.display()));
4848

49-
for dep in &["libcc2rs", "libc", "brotli_sys", "rustls_ffi", "nix"] {
49+
for dep in &[
50+
"libcc2rs",
51+
"libc",
52+
"brotli_sys",
53+
"rustls_ffi",
54+
"nix",
55+
"jiff",
56+
] {
5057
if let Some(rlib) = find_rlib(deps.as_path(), dep) {
5158
args.push("--extern".to_string());
5259
args.push(format!("{}={}", dep, rlib.display()));

‎rules/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ libcc2rs = { version = "0.1.0", path = "../libcc2rs" }
1414
brotli-sys = "0.3"
1515
rustls-ffi = { version = "0.15.3", default-features = false }
1616
nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] }
17+
jiff = "0.2"

‎rules/time/src.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ int f8(struct timeval *tv, void *tz) {
4141
#else
4242
#error "Unsupported platform for gettimeofday"
4343
#endif
44+
45+
clockid_t f9() {
46+
return CLOCK_REALTIME;
47+
}

‎rules/time/tgt_refcount.rs‎

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,139 @@ fn t2() -> libcc2rs::Timeval {
1414
fn t3() -> libcc2rs::Timespec {
1515
Default::default()
1616
}
17+
18+
fn f1(a0: Ptr<::libc::time_t>) -> ::libc::time_t {
19+
let __out = a0;
20+
match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) {
21+
Ok(__ts) => {
22+
let __s = __ts.tv_sec();
23+
if !__out.is_null() {
24+
__out.write(__s);
25+
}
26+
__s
27+
}
28+
Err(__e) => {
29+
libcc2rs::cpp2rust_errno().write(__e as i32);
30+
-1
31+
}
32+
}
33+
}
34+
35+
fn f2(a0: nix::time::ClockId, a1: Ptr<Timespec>) -> i32 {
36+
match nix::time::clock_gettime(a0) {
37+
Ok(__ts) => {
38+
a1.with_mut(|__t| {
39+
*__t.tv_sec.borrow_mut() = __ts.tv_sec() as i64;
40+
*__t.tv_nsec.borrow_mut() = __ts.tv_nsec() as i64;
41+
});
42+
0
43+
}
44+
Err(__e) => {
45+
libcc2rs::cpp2rust_errno().write(__e as i32);
46+
-1
47+
}
48+
}
49+
}
50+
51+
fn f4(a0: Ptr<::libc::time_t>, a1: Ptr<Tm>) -> Ptr<Tm> {
52+
let __res = a1.clone();
53+
match jiff::Timestamp::from_second(a0.read()) {
54+
Ok(__ts) => {
55+
let __dt = __ts.to_zoned(jiff::tz::TimeZone::UTC);
56+
__res.with_mut(|__tm| *__tm = Tm::from_zoned(&__dt));
57+
__res
58+
}
59+
Err(_) => {
60+
libcc2rs::cpp2rust_errno().write(::libc::EOVERFLOW);
61+
Ptr::null()
62+
}
63+
}
64+
}
65+
66+
fn f6(a0: Ptr<u8>, a1: usize, a2: Ptr<u8>, a3: Ptr<Tm>) -> usize {
67+
let __dt = a3.with(|__tm| __tm.to_civil());
68+
let __text = match __dt {
69+
Ok(__d) => {
70+
jiff::fmt::strtime::format(a2.to_rust_string().as_str(), __d).unwrap_or_default()
71+
}
72+
Err(_) => String::new(),
73+
};
74+
if __text.is_empty() || __text.len() + 1 > a1 {
75+
0
76+
} else {
77+
let mut __dst = a0.clone();
78+
for __b in __text.as_bytes() {
79+
__dst.write(*__b);
80+
__dst += 1;
81+
}
82+
__dst.write(0);
83+
__text.len()
84+
}
85+
}
86+
87+
fn f7(a0: Ptr<u8>, a1: Ptr<Timeval>) -> i32 {
88+
let __times = a1;
89+
let __at = __times.with(|__tv| {
90+
nix::sys::time::TimeVal::new(
91+
*__tv.tv_sec.borrow() as ::libc::time_t,
92+
*__tv.tv_usec.borrow() as ::libc::suseconds_t,
93+
)
94+
});
95+
let __mt = __times.offset(1).with(|__tv| {
96+
nix::sys::time::TimeVal::new(
97+
*__tv.tv_sec.borrow() as ::libc::time_t,
98+
*__tv.tv_usec.borrow() as ::libc::suseconds_t,
99+
)
100+
});
101+
match nix::sys::stat::utimes(a0.to_rust_string().as_str(), &__at, &__mt) {
102+
Ok(()) => 0,
103+
Err(__e) => {
104+
libcc2rs::cpp2rust_errno().write(__e as i32);
105+
-1
106+
}
107+
}
108+
}
109+
110+
// a1 is ignored intentionally, see: https://man7.org/linux/man-pages/man2/gettimeofday.2.html
111+
//
112+
// "The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL."
113+
#[cfg(target_os = "linux")]
114+
fn f8(a0: Ptr<Timeval>, a1: Ptr<::libc::timezone>) -> i32 {
115+
match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) {
116+
Ok(__ts) => {
117+
a0.with_mut(|__tv| {
118+
*__tv.tv_sec.borrow_mut() = __ts.tv_sec() as i64;
119+
*__tv.tv_usec.borrow_mut() = (__ts.tv_nsec() / 1000) as i64;
120+
});
121+
0
122+
}
123+
Err(__e) => {
124+
libcc2rs::cpp2rust_errno().write(__e as i32);
125+
-1
126+
}
127+
}
128+
}
129+
130+
// a1 is ignored intentionally, see: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/gettimeofday.2.html
131+
//
132+
// "Note: timezone is no longer used; this information is kept outside the kernel."
133+
#[cfg(target_os = "macos")]
134+
fn f8(a0: Ptr<Timeval>, a1: AnyPtr) -> i32 {
135+
match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) {
136+
Ok(__ts) => {
137+
a0.with_mut(|__tv| {
138+
*__tv.tv_sec.borrow_mut() = __ts.tv_sec() as i64;
139+
*__tv.tv_usec.borrow_mut() = (__ts.tv_nsec() / 1000) as i64;
140+
});
141+
0
142+
}
143+
Err(__e) => {
144+
libcc2rs::cpp2rust_errno().write(__e as i32);
145+
-1
146+
}
147+
}
148+
}
149+
150+
unsafe fn f9() -> nix::time::ClockId {
151+
nix::time::ClockId::CLOCK_REALTIME
152+
}

‎rules/time/tgt_unsafe.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ unsafe fn f8(a0: *mut libc::timeval, a1: *mut libc::timezone) -> i32 {
5151
unsafe fn f8(a0: *mut libc::timeval, a1: *mut libc::c_void) -> i32 {
5252
libc::gettimeofday(a0, a1)
5353
}
54+
55+
unsafe fn f9() -> libc::clockid_t {
56+
libc::CLOCK_REALTIME
57+
}

‎tests/lit/lit/formats/Cpp2RustTest.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ def build_rust(self):
212212
libc_dep_deps.glob("libnix-*.rlib"),
213213
key=lambda p: p.stat().st_mtime,
214214
)
215+
jiff_rlib = max(
216+
libc_dep_deps.glob("libjiff-*.rlib"),
217+
key=lambda p: p.stat().st_mtime,
218+
)
215219
cmd = [
216220
"rustc",
217221
"+" + read_rust_version(),
@@ -240,6 +244,8 @@ def build_rust(self):
240244
f"libc={libc_rlib}",
241245
"--extern",
242246
f"nix={nix_rlib}",
247+
"--extern",
248+
f"jiff={jiff_rlib}",
243249
]
244250
_, err, returncode = lit.util.executeCommand(cmd, str(self.tmp_dir))
245251
if exp.should_not_compile:

0 commit comments

Comments
 (0)