diff --git a/changelogs/unreleased/gh-8887-fix-interval-int64.md b/changelogs/unreleased/gh-8887-fix-interval-int64.md new file mode 100644 index 000000000000..20142aea1100 --- /dev/null +++ b/changelogs/unreleased/gh-8887-fix-interval-int64.md @@ -0,0 +1,4 @@ +## bugfix/msgpack + +* Fixed decoding datetime intervals with fields larger than possible int32 + values (gh-8887). diff --git a/src/lib/core/mp_interval.c b/src/lib/core/mp_interval.c index 6d633d0ea837..2c0486224c37 100644 --- a/src/lib/core/mp_interval.c +++ b/src/lib/core/mp_interval.c @@ -116,7 +116,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv) memset(itv, 0, sizeof(*itv)); for (uint32_t i = 0; i < count; ++i) { uint32_t field = mp_load_u8(data); - int32_t value; + int64_t value; enum mp_type type = mp_typeof(**data); if (type == MP_UINT) { if (mp_check_uint(*data, end) > 0) @@ -127,7 +127,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv) } else { return NULL; } - if (mp_read_int32(data, &value) != 0) + if (mp_read_int64(data, &value) != 0) return NULL; switch (field) { case FIELD_YEAR: @@ -155,7 +155,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv) itv->nsec = value; break; case FIELD_ADJUST: - if (value > (int32_t)DT_SNAP) + if (value > (int64_t)DT_SNAP) return NULL; itv->adjust = (dt_adjust_t)value; break; diff --git a/test/unit/interval.c b/test/unit/interval.c index 6a3d2502c340..135e40e8ae57 100644 --- a/test/unit/interval.c +++ b/test/unit/interval.c @@ -96,11 +96,62 @@ test_interval_encode_decode(void) is(result.adjust, DT_EXCESS, "Adjust value is right"); } +static void +test_interval_encode_decode_limits(void) +{ + struct interval itv; + memset(&itv, 0, sizeof(itv)); + struct interval result; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.day = -4295055470; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.day = 4295055470; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.hour = -103081331286; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.hour = 103081331286; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.min = -6184879877160; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.min = 6184879877160; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.sec = -371092792629600; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.sec = 371092792629600; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.nsec = -2147483647; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); + + itv.nsec = 2147483647; + interval_mp_recode(&itv, &result); + ok(is_interval_equal(&itv, &result), "Intervals are equal."); +} + int main(void) { - plan(21); + plan(32); test_interval_sizeof(); test_interval_encode_decode(); + test_interval_encode_decode_limits(); return check_plan(); }