Unverified Commit b38ccb96 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Fix panic in DateTime::from_secs_f64 (#3806)

## Motivation and Context
- #3805 

## Description
Recover from floating point values extremely close to whole numbers by
incrementing the epoch seconds value.

## Testing
- proptest

## Checklist
<!--- If a checkbox below is not applicable, then please DELETE it
rather than leaving it unchecked -->
- [x] For changes to the smithy-rs codegen or runtime crates, I have
created a changelog entry Markdown file in the `.changelog` directory,
specifying "client," "server," or both in the `applies_to` key.
- [x] For changes to the AWS SDK, generated SDK code, or SDK runtime
crates, I have created a changelog entry Markdown file in the
`.changelog` directory, specifying "aws-sdk-rust" in the `applies_to`
key.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
parent 35f53b45
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
---
applies_to: ["client", "server"]
authors: ["rcoh"]
references: ["smithy-rs#3805"]
breaking: false
new_feature: false
bug_fix: true
---
Fix bug in `DateTime::from_secs_f64` where certain floating point values could lead to a panic.
+1 −1
Original line number Diff line number Diff line
@@ -149,7 +149,7 @@ dependencies = [

[[package]]
name = "aws-runtime"
version = "1.4.1"
version = "1.4.2"
dependencies = [
 "arbitrary",
 "aws-credential-types",
+1 −1
Original line number Diff line number Diff line
[package]
name = "aws-smithy-types"
version = "1.2.4"
version = "1.2.5"
authors = [
    "AWS Rust SDK Team <aws-sdk-rust@amazon.com>",
    "Russell Cohen <rcoh@amazon.com>",
+29 −2
Original line number Diff line number Diff line
@@ -110,13 +110,22 @@ impl DateTime {
    ///     DateTime::from_fractional_secs(1, 0.5),
    /// );
    /// ```
    pub fn from_fractional_secs(epoch_seconds: i64, fraction: f64) -> Self {
        let subsecond_nanos = (fraction * 1_000_000_000_f64) as u32;
    pub fn from_fractional_secs(mut epoch_seconds: i64, fraction: f64) -> Self {
        // Because of floating point issues, `fraction` can end up being 1.0 leading to
        // a full second of subsecond nanos. In that case, rollover the subsecond into the second.
        let mut subsecond_nanos = (fraction * 1_000_000_000_f64) as u32;
        if subsecond_nanos == 1_000_000_000 {
            epoch_seconds += 1;
            subsecond_nanos = 0;
        }
        DateTime::from_secs_and_nanos(epoch_seconds, subsecond_nanos)
    }

    /// Creates a `DateTime` from a number of seconds and sub-second nanos since the Unix epoch.
    ///
    /// # Panics
    /// This function will panic if `subsecond_nanos` is >= 1_000_000_000
    ///
    /// # Example
    /// ```
    /// # use aws_smithy_types::DateTime;
@@ -680,6 +689,17 @@ mod test {
        assert!(fifth == fifth);
    }

    /// https://github.com/smithy-lang/smithy-rs/issues/3805
    #[test]
    fn panic_in_fromsecs_f64() {
        assert_eq!(DateTime::from_secs_f64(-1.0), DateTime::from_secs(-1));

        assert_eq!(
            DateTime::from_secs_f64(-1.95877825437922e-309),
            DateTime::from_secs(0)
        );
    }

    const MIN_RFC_3339_MILLIS: i64 = -62135596800000;
    const MAX_RFC_3339_MILLIS: i64 = 253402300799999;

@@ -699,4 +719,11 @@ mod test {
            assert_eq!(left.cmp(&right), left_str.cmp(&right_str));
        }
    }

    proptest! {
        #[test]
        fn from_secs_f64_proptest(secs: f64) {
            let _date = DateTime::from_secs_f64(secs);
        }
    }
}