Skip to content

Commit

Permalink
msgpack: fix decoding intervals with int64
Browse files Browse the repository at this point in the history
It is possible for interval to have days, hours, minutes and seconds
larger than INT_MAX (or less than INT_MIN). Before this patch, msgpack
decoding had failed to parse intervals with msgpack int64 and uint64.
int64_t should be enough to store any value allowed for datetime
intervals.

Closes tarantool#8887

NO_DOC=small bug fix
  • Loading branch information
DifferentialOrange committed Jul 17, 2023
1 parent 56488e1 commit e9e872b
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
4 changes: 4 additions & 0 deletions 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).
6 changes: 3 additions & 3 deletions src/lib/core/mp_interval.c
Expand Up @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
53 changes: 52 additions & 1 deletion test/unit/interval.c
Expand Up @@ -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();
}

0 comments on commit e9e872b

Please sign in to comment.