diff --git a/ext/date/tests/time/duration/serialize.phpt b/ext/date/tests/time/duration/serialize.phpt index 982a84bef392..c2af67efd6fe 100644 --- a/ext/date/tests/time/duration/serialize.phpt +++ b/ext/date/tests/time/duration/serialize.phpt @@ -46,6 +46,20 @@ try { echo $e::class, ': ', $e->getMessage(), PHP_EOL; } +try { + // Nanoseconds that would be truncated to a valid value by a 32-bit conversion (2^32 + 5). + unserialize('O:13:"Time\Duration":3:{s:7:"seconds";i:1;s:11:"nanoseconds";i:4294967301;s:8:"negative";b:0;}'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + // A negative zero duration is rejected. + unserialize('O:13:"Time\Duration":3:{s:7:"seconds";i:0;s:11:"nanoseconds";i:0;s:8:"negative";b:1;}'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + try { Time\Duration::fromSeconds(1, 1) ->__unserialize([ @@ -69,3 +83,5 @@ Exception: Invalid serialization data for Time\Duration object Exception: Invalid serialization data for Time\Duration object Exception: Invalid serialization data for Time\Duration object Exception: Invalid serialization data for Time\Duration object +Exception: Invalid serialization data for Time\Duration object +Exception: Invalid serialization data for Time\Duration object diff --git a/ext/date/time_duration.c b/ext/date/time_duration.c index a9f69db7a3d8..8565f3e8c5f0 100644 --- a/ext/date/time_duration.c +++ b/ext/date/time_duration.c @@ -175,11 +175,18 @@ PHP_METHOD(Time_Duration, __unserialize) goto fail; } - /* Verify that both properties are positive, since the timelib_duration_ctor_static() takes unsigned. */ + /* Verify that both properties are non-negative, since the timelib_duration_ctor_static() takes + * unsigned. */ if (Z_LVAL_P(seconds) < 0 || Z_LVAL_P(nanoseconds) < 0) { goto fail; } + /* timelib_duration_ctor_static() takes a uint32_t for nanoseconds, so larger values would + * implicitly wrap around instead of being rejected. */ + if (Z_LVAL_P(nanoseconds) >= NANOS_IN_SEC) { + goto fail; + } + int error = timelib_duration_ctor_static(&duration->duration, Z_LVAL_P(seconds), Z_LVAL_P(nanoseconds), Z_TYPE_P(negative) == IS_TRUE); if (error != TIMELIB_ERROR_NO_ERROR) { throw_timelib_error(error); @@ -191,6 +198,10 @@ PHP_METHOD(Time_Duration, __unserialize) goto fail; } + if ((Z_TYPE_P(negative) == IS_TRUE) != duration->duration.negative) { + goto fail; + } + return; fail: