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 df1f7ff96c
commit d946e5ddd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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> {