Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix format panic problem #614

Closed
wants to merge 3 commits into from
Closed

fix format panic problem #614

wants to merge 3 commits into from

Conversation

retrhelo
Copy link

Add some modification to format::inner_format(), which will prevent the program from panic when an inproper format string is provided. This is the problem mentioned in issue #575 .

The new strategy I'm using is to skip those inproper format substrings. You can find some of the examples in the test I add. I think this strategy is better than directly panic, especially when handling user input strings. Skipping the wrong parts will also indicate an invalid format string, and giving the programmer an opportunity to fix the problem while running, instead of panic and terminating the program.

retrhelo added 2 commits October 31, 2021 19:11
format: change the behaviour of format::format_inner(),
	disable it from throwing fmt::Error if item is in wrong
	format, or has an argument missing problem. Doing this
	will prevent program from panic if trying to format
	an instance, say `Date`, with an inproper format string.
@quodlibetor
Copy link
Contributor

This unfortunately causes errors to become silent.

A better solution would be to introduce a format_opt method that correctly returns a Result<DelayedFormat, FormatError>.

src/datetime.rs Outdated
// pass a wrong format
assert_eq!(
format!("{}", naive_date.format("%Y %{whatever} %d")),
String::from("2000 whatever} 12")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If invalid, I would imagine this would simply produce "%{whatever}", not "whatever}"

@retrhelo
Copy link
Author

retrhelo commented Nov 2, 2021 via email

@Milo123459
Copy link
Member

Maybe create another function that returns a Result?

@retrhelo
Copy link
Author

retrhelo commented Nov 19, 2021

Maybe create another function that returns a Result?

I roughly created a try_format function for this purpose. However, I find that there's many format functions for each structure like DateTime, Date, etc. Adding such a function will get a lot of files involved, since we're adding it to every structure that implements format function. I think create a new PR for this task is better choice.

StrftimeItems:
    Modify the implementation of Iterator for StrftimeItems.
    Item::Error is changed to be Item::Error(&'a str) for more
    flexible usages.

Others:
    Add some tests for NaiveDateTime, NaiveDate and NaiveTime.
@hustcer
Copy link

hustcer commented May 6, 2022

Any update on this PR?

@djc
Copy link
Member

djc commented May 6, 2022

What's the path here? Is there some outer API here that's not propagating the error from the inner API, but panicking instead?

@retrhelo
Copy link
Author

retrhelo commented May 7, 2022

Is there some outer API here that's not propagating the error from the inner API, but panicking instead?

Yes, it's the panic problem. The original format function panics when passed in an inproper format string, making it hard to "format" a user-input string that's possibly inproper.

@djc
Copy link
Member

djc commented Jun 9, 2022

Yeah, I don't think this is an improvement. If we're going to stop panicking, we should explicitly signal an error some other way.

@esheppa
Copy link
Collaborator

esheppa commented Jul 3, 2022

Just to add another option here, and I recognize this isn't super user friendly or discoverable, (we can potentially fix that with a few helper functions or more docs) but the potentially invalid user input problem can be solved in the currently released chrono, using StrftimeItems::new() and the write! macro depending on the task.

If you want to just check whether the format string is valid or not, using StrftimeItems suffices, however if you want to format without panicking, using write! instead of to_string or format! allows catching this (playground link).

use chrono::{Utc, format::{Item, strftime::StrftimeItems}}; // 0.4.19
use std::fmt::Write;
const BAD_FMT_STR: &str = "%Y-%m-%";
const GOOD_FMT_STR: &str = "%Y-%m-%d";

fn main() {
    assert!(StrftimeItems::new(BAD_FMT_STR).any(|i| matches!(i, Item::Error)));
    assert!(StrftimeItems::new(GOOD_FMT_STR).all(|i| !matches!(i, Item::Error)));
    
    let mut out = String::new();
    assert!(write!(&mut out, "{}", Utc::now().date().naive_local().format(GOOD_FMT_STR)).is_ok());
    assert!(write!(&mut out, "{}", Utc::now().date().naive_local().format(BAD_FMT_STR)).is_err());
}

@esheppa
Copy link
Collaborator

esheppa commented Jul 24, 2022

I've added a draft PR which shows some options here: #735

@pitdicker
Copy link
Collaborator

@retrhelo Thank you for your work here!
We are going in a different direction to fix this panic, see #1127.

@pitdicker pitdicker closed this Jul 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants