Fix for crash with invalid dates on Windows (#1837)

https://forums.ankiweb.net/t/bug-report-crashing-when-opening-deck-browser/19768

Caused by a note mtime that was 1000x larger than it should have been.
Check DB will now fix this case (but there are others it still does not
cover, such as invalid card/note IDs).

https://docs.rs/chrono/0.4.19/x86_64-pc-windows-msvc/src/chrono/sys/windows.rs.html#128
This commit is contained in:
Damien Elmes 2022-05-07 10:30:23 +10:00 committed by GitHub
parent e979d31d8b
commit adf6220bb9
3 changed files with 28 additions and 8 deletions

View file

@ -206,7 +206,8 @@ impl Collection {
let nids_by_notetype = self.storage.all_note_ids_by_notetype()?;
let norm = self.get_config_bool(BoolKey::NormalizeNoteText);
let usn = self.usn()?;
let stamp = TimestampMillis::now();
let stamp_millis = TimestampMillis::now();
let stamp_secs = TimestampSecs::now();
let expanded_tags = self.storage.expanded_tags()?;
self.storage.clear_all_tags()?;
@ -221,7 +222,7 @@ impl Collection {
None => {
let first_note = self.storage.get_note(group.peek().unwrap().1)?.unwrap();
out.notetypes_recovered += 1;
self.recover_notetype(stamp, first_note.fields().len(), ntid)?
self.recover_notetype(stamp_millis, first_note.fields().len(), ntid)?
}
Some(nt) => nt,
};
@ -252,6 +253,10 @@ impl Collection {
out.field_count_mismatch += 1;
}
if note.mtime > stamp_secs {
note.mtime = stamp_secs;
}
// note type ID may have changed if we created a recovery notetype
note.notetype_id = nt.id;

View file

@ -90,7 +90,7 @@ impl Collection {
.and_then(|v| FixedOffset::west_opt(v * 60))
.unwrap_or_else(|| FixedOffset::west(0));
let local_tz = TimestampSecs::now().local_utc_offset();
let local_tz = TimestampSecs::now().local_utc_offset()?;
Ok(if self.server {
config_tz

View file

@ -5,7 +5,7 @@ use std::time;
use chrono::prelude::*;
use crate::define_newtype;
use crate::{define_newtype, prelude::*};
define_newtype!(TimestampSecs, i64);
define_newtype!(TimestampMillis, i64);
@ -31,18 +31,33 @@ impl TimestampSecs {
TimestampMillis(self.0 * 1000)
}
#[cfg(windows)]
pub(crate) fn local_datetime(self) -> Result<DateTime<Local>> {
std::panic::catch_unwind(|| Local.timestamp(self.0, 0))
.map_err(|_err| AnkiError::invalid_input("invalid date"))
}
#[cfg(not(windows))]
pub(crate) fn local_datetime(self) -> Result<DateTime<Local>> {
Ok(Local.timestamp(self.0, 0))
}
/// YYYY-mm-dd
pub(crate) fn date_string(self) -> String {
Local.timestamp(self.0, 0).format("%Y-%m-%d").to_string()
self.local_datetime()
.map(|dt| dt.format("%Y-%m-%d").to_string())
.unwrap_or_else(|_err| "invalid date".to_string())
}
/// HH-MM
pub(crate) fn time_string(self) -> String {
Local.timestamp(self.0, 0).format("%H:%M").to_string()
self.local_datetime()
.map(|dt| dt.format("%H:%M").to_string())
.unwrap_or_else(|_err| "invalid date".to_string())
}
pub fn local_utc_offset(self) -> FixedOffset {
*Local.timestamp(self.0, 0).offset()
pub fn local_utc_offset(self) -> Result<FixedOffset> {
Ok(*self.local_datetime()?.offset())
}
pub fn datetime(self, utc_offset: FixedOffset) -> DateTime<FixedOffset> {