diff --git a/msgpack/unpack.h b/msgpack/unpack.h index eb4330ac..0541fc19 100644 --- a/msgpack/unpack.h +++ b/msgpack/unpack.h @@ -271,16 +271,21 @@ static int unpack_timestamp(const char* buf, unsigned int buflen, msgpack_timest uint64_t value =_msgpack_load64(uint64_t, buf); ts->tv_nsec = (uint32_t)(value >> 34); ts->tv_sec = value & 0x00000003ffffffffLL; - return 0; + break; } case 12: ts->tv_nsec = _msgpack_load32(uint32_t, buf); ts->tv_sec = _msgpack_load64(int64_t, buf + 4); - return 0; + break; default: PyErr_Format(PyExc_ValueError, "invalid timestamp data (length %u)", buflen); return -1; } + if (ts->tv_nsec > 999999999) { + PyErr_Format(PyExc_ValueError, "nanoseconds must be a non-negative integer less than 999999999."); + return -1; + } + return 0; } #include "datetime.h" diff --git a/test/test_timestamp.py b/test/test_timestamp.py index 2083356a..3e753e11 100644 --- a/test/test_timestamp.py +++ b/test/test_timestamp.py @@ -71,6 +71,15 @@ def test_unpack_timestamp(): msgpack.unpackb(b"\xc7\x05\xff\0\0\0\0\0") # ext8 (len=5) +def test_unpack_timestamp_out_of_range_nanoseconds(): + # An out-of-range nanoseconds field must be rejected in every timestamp= + # mode (spec: nanoseconds must not exceed 999999999), not only the default. + for data in (b"\xd7\xff" + b"\xff" * 8, b"\xc7\x0c\xff" + b"\xff" * 12): + for mode in (0, 1, 2, 3): + with pytest.raises(ValueError): + msgpack.unpackb(data, timestamp=mode) + + def test_timestamp_from(): t = Timestamp(42, 14000) assert Timestamp.from_unix(42.000014) == t