datetime: fix panic on invalid cstr conversion

async
Manos Pitsidianakis 2020-05-06 18:46:38 +03:00
parent 330134af5a
commit 5d07a5147b
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
5 changed files with 39 additions and 27 deletions

View File

@ -201,7 +201,8 @@ impl<V: VCardVersion> TryInto<Card> for VCard<V> {
T102200Z T102200Z
T102200-0800 T102200-0800
*/ */
card.birthday = crate::datetime::timestamp_from_string(val.value.as_str(), "%Y%m%d"); card.birthday = crate::datetime::timestamp_from_string(val.value.as_str(), "%Y%m%d")
.unwrap_or_default();
} }
if let Some(val) = self.0.remove("EMAIL") { if let Some(val) = self.0.remove("EMAIL") {
card.set_email(val.value); card.set_email(val.value);

View File

@ -235,7 +235,8 @@ impl std::convert::From<EmailObject> for crate::Envelope {
env.set_datetime(d); env.set_datetime(d);
} }
if let Some(ref mut sent_at) = t.sent_at { if let Some(ref mut sent_at) = t.sent_at {
let unix = crate::datetime::rfc3339_to_timestamp(sent_at.as_bytes().to_vec()); let unix =
crate::datetime::rfc3339_to_timestamp(sent_at.as_bytes().to_vec()).unwrap_or(0);
env.set_datetime(unix); env.set_datetime(unix);
env.set_date(std::mem::replace(sent_at, String::new()).as_bytes()); env.set_date(std::mem::replace(sent_at, String::new()).as_bytes());
} }

View File

@ -22,6 +22,8 @@
use std::convert::TryInto; use std::convert::TryInto;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use crate::error::Result;
pub type UnixTimestamp = u64; pub type UnixTimestamp = u64;
use libc::{timeval, timezone}; use libc::{timeval, timezone};
@ -53,25 +55,26 @@ pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> Strin
let i: i64 = timestamp.try_into().unwrap_or(0); let i: i64 = timestamp.try_into().unwrap_or(0);
localtime_r(&i as *const i64, &mut new_tm as *mut ::libc::tm); localtime_r(&i as *const i64, &mut new_tm as *mut ::libc::tm);
} }
let fmt = fmt.map(|slice| CString::new(slice).unwrap()); let fmt = fmt
.map(|slice| CString::new(slice))
.map(|res| res.ok())
.and_then(|opt| opt);
let format: &CStr = if let Some(ref s) = fmt { let format: &CStr = if let Some(ref s) = fmt {
&s &s
} else { } else {
unsafe { CStr::from_bytes_with_nul_unchecked(b"%a, %d %b %Y %T %z\0") } unsafe { CStr::from_bytes_with_nul_unchecked(b"%a, %d %b %Y %T %z\0") }
}; };
let s: CString; let mut vec: [u8; 256] = [0; 256];
unsafe { let ret = unsafe {
let mut vec: [u8; 256] = [0; 256]; strftime(
let ret = strftime(
vec.as_mut_ptr() as *mut _, vec.as_mut_ptr() as *mut _,
256, 256,
format.as_ptr(), format.as_ptr(),
&new_tm as *const _, &new_tm as *const _,
); )
s = CString::new(&vec[0..ret]).unwrap(); };
}
s.to_string_lossy().to_string() String::from_utf8_lossy(&vec[0..ret]).into_owned()
} }
fn tm_to_secs(tm: ::libc::tm) -> std::result::Result<i64, ()> { fn tm_to_secs(tm: ::libc::tm) -> std::result::Result<i64, ()> {
@ -184,11 +187,11 @@ fn month_to_secs(month: usize, is_leap: bool) -> i64 {
return t; return t;
} }
pub fn rfc822_to_timestamp<T>(s: T) -> UnixTimestamp pub fn rfc822_to_timestamp<T>(s: T) -> Result<UnixTimestamp>
where where
T: Into<Vec<u8>>, T: Into<Vec<u8>>,
{ {
let s = CString::new(s).unwrap(); let s = CString::new(s)?;
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
for fmt in &[ for fmt in &[
&b"%a, %e %h %Y %H:%M:%S \0"[..], &b"%a, %e %h %Y %H:%M:%S \0"[..],
@ -231,19 +234,19 @@ where
0 0
} }
}; };
return tm_to_secs(new_tm) return Ok(tm_to_secs(new_tm)
.map(|res| (res - tm_gmtoff) as u64) .map(|res| (res - tm_gmtoff) as u64)
.unwrap_or(0); .unwrap_or(0));
} }
} }
return 0; return Ok(0);
} }
pub fn rfc3339_to_timestamp<T>(s: T) -> UnixTimestamp pub fn rfc3339_to_timestamp<T>(s: T) -> Result<UnixTimestamp>
where where
T: Into<Vec<u8>>, T: Into<Vec<u8>>,
{ {
let s = CString::new(s).unwrap(); let s = CString::new(s)?;
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
for fmt in &[&b"%Y-%m-%dT%H:%M:%S\0"[..], &b"%Y-%m-%d\0"[..]] { for fmt in &[&b"%Y-%m-%dT%H:%M:%S\0"[..], &b"%Y-%m-%d\0"[..]] {
unsafe { unsafe {
@ -284,31 +287,31 @@ where
0 0
} }
}; };
return tm_to_secs(new_tm) return Ok(tm_to_secs(new_tm)
.map(|res| (res - tm_gmtoff) as u64) .map(|res| (res - tm_gmtoff) as u64)
.unwrap_or(0); .unwrap_or(0));
} }
} }
return 0; return Ok(0);
} }
// FIXME: Handle non-local timezone? // FIXME: Handle non-local timezone?
pub fn timestamp_from_string<T>(s: T, fmt: &str) -> Option<UnixTimestamp> pub fn timestamp_from_string<T>(s: T, fmt: &str) -> Result<Option<UnixTimestamp>>
where where
T: Into<Vec<u8>>, T: Into<Vec<u8>>,
{ {
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
let fmt = CString::new(fmt).unwrap(); let fmt = CString::new(fmt)?;
unsafe { unsafe {
let ret = strptime( let ret = strptime(
CString::new(s).unwrap().as_ptr(), CString::new(s)?.as_ptr(),
fmt.as_ptr(), fmt.as_ptr(),
&mut new_tm as *mut _, &mut new_tm as *mut _,
); );
if ret.is_null() { if ret.is_null() {
return None; return Ok(None);
} }
return Some(mktime(&new_tm as *const _) as u64); return Ok(Some(mktime(&new_tm as *const _) as u64));
} }
} }

View File

@ -664,7 +664,7 @@ pub fn date(input: &[u8]) -> Result<UnixTimestamp> {
parsed_result[pos] = b'+'; parsed_result[pos] = b'+';
} }
Ok(crate::datetime::rfc822_to_timestamp(parsed_result.trim())) crate::datetime::rfc822_to_timestamp(parsed_result.trim())
} }
named!(pub message_id<&[u8]>, named!(pub message_id<&[u8]>,

View File

@ -167,6 +167,13 @@ impl From<serde_json::error::Error> for MeliError {
} }
} }
impl From<std::ffi::NulError> for MeliError {
#[inline]
fn from(kind: std::ffi::NulError) -> MeliError {
MeliError::new(format!("{}", kind))
}
}
impl From<&str> for MeliError { impl From<&str> for MeliError {
#[inline] #[inline]
fn from(kind: &str) -> MeliError { fn from(kind: &str) -> MeliError {