melib/datetime: fix overflow panic on early date input

async
Manos Pitsidianakis 2020-02-08 13:44:53 +02:00
parent eb501b6d50
commit 6afac835e0
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 28 additions and 18 deletions

View File

@ -74,7 +74,7 @@ pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> Strin
s.to_string_lossy().to_string() s.to_string_lossy().to_string()
} }
fn tm_to_secs(tm: ::libc::tm) -> UnixTimestamp { fn tm_to_secs(tm: ::libc::tm) -> std::result::Result<i64, ()> {
let mut is_leap = false; let mut is_leap = false;
let mut year = tm.tm_year; let mut year = tm.tm_year;
let mut month = tm.tm_mon; let mut month = tm.tm_mon;
@ -87,19 +87,19 @@ fn tm_to_secs(tm: ::libc::tm) -> UnixTimestamp {
} }
year += adj; year += adj;
} }
let mut t = year_to_secs(year as u64, &mut is_leap); let mut t = year_to_secs(year.into(), &mut is_leap)?;
t += month_to_secs(month as usize, is_leap); t += month_to_secs(month.try_into().unwrap_or(0), is_leap);
t += 86400 * (tm.tm_mday as u64 - 1); t += 86400 * (tm.tm_mday - 1) as i64;
t += 3600 * (tm.tm_hour as u64); t += 3600 * (tm.tm_hour) as i64;
t += 60 * (tm.tm_min as u64); t += 60 * (tm.tm_min) as i64;
t += tm.tm_sec as u64; t += tm.tm_sec as i64;
t Ok(t)
} }
fn year_to_secs(year: u64, is_leap: &mut bool) -> u64 { fn year_to_secs(year: i64, is_leap: &mut bool) -> std::result::Result<i64, ()> {
if year < 100 { if year < -100 {
/* Sorry time travelers. */ /* Sorry time travelers. */
return 0; return Err(());
} }
if year - 2 <= 136 { if year - 2 <= 136 {
@ -111,7 +111,9 @@ fn year_to_secs(year: u64, is_leap: &mut bool) -> u64 {
} else { } else {
*is_leap = false; *is_leap = false;
} }
return 31536000 * (y - 70) + 86400 * leaps; return Ok((31536000 * (y - 70) + 86400 * leaps)
.try_into()
.unwrap_or(0));
} }
let cycles = (year - 100) / 400; let cycles = (year - 100) / 400;
@ -154,11 +156,14 @@ fn year_to_secs(year: u64, is_leap: &mut bool) -> u64 {
leaps += 97 * cycles + 24 * centuries - if *is_leap { 1 } else { 0 }; leaps += 97 * cycles + 24 * centuries - if *is_leap { 1 } else { 0 };
return (year - 100) * 31536000 + leaps * 86400 + 946684800 + 86400; return Ok(match (year - 100).overflowing_mul(31536000) {
(_, true) => return Err(()),
(res, false) => res + leaps * 86400 + 946684800 + 86400,
});
} }
fn month_to_secs(month: usize, is_leap: bool) -> u64 { fn month_to_secs(month: usize, is_leap: bool) -> i64 {
const SECS_THROUGH_MONTH: [u64; 12] = [ const SECS_THROUGH_MONTH: [i64; 12] = [
0, 0,
31 * 86400, 31 * 86400,
59 * 86400, 59 * 86400,
@ -172,7 +177,7 @@ fn month_to_secs(month: usize, is_leap: bool) -> u64 {
304 * 86400, 304 * 86400,
334 * 86400, 334 * 86400,
]; ];
let mut t = SECS_THROUGH_MONTH[month as usize]; let mut t = SECS_THROUGH_MONTH[month];
if is_leap && month >= 2 { if is_leap && month >= 2 {
t += 86400; t += 86400;
} }
@ -226,7 +231,9 @@ where
0 0
} }
}; };
return (tm_to_secs(new_tm) as i64 - tm_gmtoff) as u64; return tm_to_secs(new_tm)
.map(|res| (res - tm_gmtoff) as u64)
.unwrap_or(0);
} }
} }
return 0; return 0;

View File

@ -1052,7 +1052,7 @@ mod tests {
use crate::make_address; use crate::make_address;
#[test] #[test]
fn test_subject() { fn test_phrase() {
let words = b"=?iso-8859-7?B?W215Y291cnNlcy5udHVhLmdyIC0gyvXs4fTp6t4g6uHpIMri4e306ere?= let words = b"=?iso-8859-7?B?W215Y291cnNlcy5udHVhLmdyIC0gyvXs4fTp6t4g6uHpIMri4e306ere?=
=?iso-8859-7?B?INb18+nq3l0gzd3hIMHt4erv3+358+c6IMzF0c/TIMHQz9TFy8XTzMHU?= =?iso-8859-7?B?INb18+nq3l0gzd3hIMHt4erv3+358+c6IMzF0c/TIMHQz9TFy8XTzMHU?=
=?iso-8859-7?B?2c0gwiDUzC4gysHNLiDFzsXUwdPH0yAyMDE3LTE4OiDTx8zFydnTxw==?="; =?iso-8859-7?B?2c0gwiDUzC4gysHNLiDFzsXUwdPH0yAyMDE3LTE4OiDTx8zFydnTxw==?=";
@ -1145,7 +1145,10 @@ mod tests {
debug!("{:?}", date(__s)); debug!("{:?}", date(__s));
assert_eq!(date(s).unwrap(), date(_s).unwrap()); assert_eq!(date(s).unwrap(), date(_s).unwrap());
assert_eq!(date(_s).unwrap(), date(__s).unwrap()); assert_eq!(date(_s).unwrap(), date(__s).unwrap());
let val = b"Fri, 23 Dec 0001 21:20:36 -0800 (PST)";
assert_eq!(date(val).unwrap(), 0);
} }
#[test] #[test]
fn test_attachments() { fn test_attachments() {
//FIXME: add file //FIXME: add file