Skip to content

Commit 01c7ae1

Browse files
DifferentialOrangeigormunkin
authored andcommitted
msgpack: fix decoding intervals with int64
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 #8887 NO_DOC=small bug fix
1 parent 73b3908 commit 01c7ae1

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## bugfix/msgpack
2+
3+
* Fixed decoding datetime intervals with fields larger than possible int32
4+
values (gh-8887).

src/lib/core/mp_interval.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv)
116116
memset(itv, 0, sizeof(*itv));
117117
for (uint32_t i = 0; i < count; ++i) {
118118
uint32_t field = mp_load_u8(data);
119-
int32_t value;
119+
int64_t value;
120120
enum mp_type type = mp_typeof(**data);
121121
if (type == MP_UINT) {
122122
if (mp_check_uint(*data, end) > 0)
@@ -127,7 +127,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv)
127127
} else {
128128
return NULL;
129129
}
130-
if (mp_read_int32(data, &value) != 0)
130+
if (mp_read_int64(data, &value) != 0)
131131
return NULL;
132132
switch (field) {
133133
case FIELD_YEAR:
@@ -155,7 +155,7 @@ interval_unpack(const char **data, uint32_t len, struct interval *itv)
155155
itv->nsec = value;
156156
break;
157157
case FIELD_ADJUST:
158-
if (value > (int32_t)DT_SNAP)
158+
if (value > (int64_t)DT_SNAP)
159159
return NULL;
160160
itv->adjust = (dt_adjust_t)value;
161161
break;

test/app-tap/datetime.test.lua

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local test = tap.test('errno')
55
local date = require('datetime')
66
local ffi = require('ffi')
77
local json = require('json')
8+
local msgpack = require('msgpack')
89
local TZ = date.TZ
910

1011
test:plan(39)
@@ -1312,7 +1313,7 @@ test:test("Time interval operations - different timezones", function(test)
13121313
end)
13131314

13141315
test:test("Time intervals creation - range checks", function(test)
1315-
test:plan(63)
1316+
test:plan(83)
13161317

13171318
local inew = date.interval.new
13181319

@@ -1377,12 +1378,18 @@ test:test("Time intervals creation - range checks", function(test)
13771378
local val_max = math.floor(range_max)
13781379

13791380
local attrib_min = {[name] = -val_max}
1380-
test:is(tostring(inew(attrib_min)), iv_str_repr(attrib_min),
1381+
local iv_min = inew(attrib_min)
1382+
test:is(tostring(iv_min), iv_str_repr(attrib_min),
13811383
('interval %s is allowed'):format(json.encode(attrib_min)))
1384+
test:is(msgpack.decode(msgpack.encode(iv_min)), iv_min,
1385+
('msgpack can process interval %s'):format(json.encode(attrib_min)))
13821386

13831387
local attrib_max = {[name] = val_max}
1384-
test:is(tostring(inew(attrib_max)), iv_str_repr(attrib_max),
1388+
local iv_max = inew(attrib_max)
1389+
test:is(tostring(iv_max), iv_str_repr(attrib_max),
13851390
('interval %s is allowed'):format(json.encode(attrib_max)))
1391+
test:is(msgpack.decode(msgpack.encode(iv_max)), iv_max,
1392+
('msgpack can process interval %s'):format(json.encode(attrib_max)))
13861393

13871394
local attrib_over_min = {[name] = -val_max - 1}
13881395
assert_raises(

test/unit/interval.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stdio.h>
22
#include <assert.h>
3+
#include <limits.h>
34

45
#include "string.h"
56
#include "datetime.h"
@@ -96,11 +97,54 @@ test_interval_encode_decode(void)
9697
is(result.adjust, DT_EXCESS, "Adjust value is right");
9798
}
9899

100+
static void
101+
test_interval_encode_decode_values_outside_int32_limits(void)
102+
{
103+
struct interval itv;
104+
memset(&itv, 0, sizeof(itv));
105+
struct interval result;
106+
interval_mp_recode(&itv, &result);
107+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
108+
109+
itv.day = (double)INT32_MIN - 1;
110+
interval_mp_recode(&itv, &result);
111+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
112+
113+
itv.day = (double)INT32_MAX + 1;
114+
interval_mp_recode(&itv, &result);
115+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
116+
117+
itv.hour = (double)INT32_MIN - 1;
118+
interval_mp_recode(&itv, &result);
119+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
120+
121+
itv.hour = (double)INT32_MAX + 1;
122+
interval_mp_recode(&itv, &result);
123+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
124+
125+
itv.min = (double)INT32_MIN - 1;
126+
interval_mp_recode(&itv, &result);
127+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
128+
129+
itv.min = (double)INT32_MAX + 1;
130+
interval_mp_recode(&itv, &result);
131+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
132+
133+
itv.sec = (double)INT32_MIN - 1;
134+
interval_mp_recode(&itv, &result);
135+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
136+
137+
itv.sec = (double)INT32_MAX + 1;
138+
interval_mp_recode(&itv, &result);
139+
ok(is_interval_equal(&itv, &result), "Intervals are equal.");
140+
}
141+
99142
int
100143
main(void)
101144
{
102-
plan(21);
145+
plan(30);
103146
test_interval_sizeof();
104147
test_interval_encode_decode();
148+
test_interval_encode_decode_values_outside_int32_limits();
105149
return check_plan();
106150
}

0 commit comments

Comments
 (0)