From 309e96087ab4592f67b0e56f418aa561a014326b Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Sat, 13 Dec 2014 22:09:32 +0900 Subject: [PATCH 1/2] - Added unpack limit. - Added new exceptions to explain limit over errors. - Fixed ext maximum size problem. Problem: The type of m_trail was uint32_t but when parsing ext, it could be 0xffffffff + 1. +1 means type. See https://github.com/msgpack/msgpack/blob/master/spec.md#ext-format-family Solution: Modified the type of m_trail as std::size_t. If sizeof(std::size_t) == 4, 0xffffffff size of ext is an error. If sizeof(std::size_t) == 8, 0xffffffff size of ext is not an error. m_trail is 0xffffffff + 1. Design cohice: I chose std::size_t as the m_trail's type instead of uint64_t intentionally. On 64 addressing bit environment, there is no problem. On 32 bit environment, there is no problem except ext with maximum size. There is only one exception in the all msgpack format. Using uint64_t to support that, it's very expensive. On 32 addressing bit environment, allocating 0xffffffff + 1 bytes of memory couldn't succeed, so I believe that throwing an exception is a reasonable design choice in the case. --- include/msgpack/unpack.hpp | 984 ++++++++++++++++++++----------------- test/CMakeLists.txt | 1 + test/Makefile.am | 5 +- test/limit.cpp | 509 +++++++++++++++++++ 4 files changed, 1056 insertions(+), 443 deletions(-) create mode 100644 test/limit.cpp diff --git a/include/msgpack/unpack.hpp b/include/msgpack/unpack.hpp index 3ba9c2a1..042e4e6f 100644 --- a/include/msgpack/unpack.hpp +++ b/include/msgpack/unpack.hpp @@ -63,12 +63,87 @@ MSGPACK_API_VERSION_NAMESPACE(v1) { typedef bool (*unpack_reference_func)(type::object_type, std::size_t, void*); +struct unpack_error : public std::runtime_error { +#if defined(MSGPACK_USE_CPP03) + unpack_error(const std::string& msg) : + std::runtime_error(msg) { } +#else + unpack_error(const char* msg) : + std::runtime_error(msg) { } +#endif +}; + +struct parse_error : public unpack_error { + parse_error():unpack_error("parse error") {} +}; + +struct insufficient_bytes : public unpack_error { + insufficient_bytes():unpack_error("insufficient bytes") {} +}; + +struct size_overflow : public unpack_error { +#if defined(MSGPACK_USE_CPP03) + size_overflow(const std::string& msg):unpack_error(msg) {} +#else + size_overflow(const char* msg):unpack_error(msg) {} +#endif +}; + +struct array_size_overflow : public size_overflow { + array_size_overflow():size_overflow("array size overflow") {} +}; + +struct map_size_overflow : public size_overflow { + map_size_overflow():size_overflow("map size overflow") {} +}; + +struct str_size_overflow : public size_overflow { + str_size_overflow():size_overflow("str size overflow") {} +}; + +struct bin_size_overflow : public size_overflow { + bin_size_overflow():size_overflow("bin size overflow") {} +}; + +struct ext_size_overflow : public size_overflow { + ext_size_overflow():size_overflow("ext size overflow") {} +}; + +class unpack_limit { +public: + unpack_limit( + std::size_t array = 0xffffffff, + std::size_t map = 0xffffffff, + std::size_t str = 0xffffffff, + std::size_t bin = 0xffffffff, + std::size_t ext = 0xffffffff) + :array_(array), + map_(map), + str_(str), + bin_(bin), + ext_(ext) {} + std::size_t array() const { return array_; } + std::size_t map() const { return map_; } + std::size_t str() const { return str_; } + std::size_t bin() const { return bin_; } + std::size_t ext() const { return ext_; } + +private: + std::size_t array_; + std::size_t map_; + std::size_t str_; + std::size_t bin_; + std::size_t ext_; +}; + namespace detail { class unpack_user { public: - unpack_user(unpack_reference_func f = nullptr, void* user_data = nullptr) - :m_func(f), m_user_data(user_data) {} + unpack_user(unpack_reference_func f = nullptr, + void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()) + :m_func(f), m_user_data(user_data), m_limit(limit) {} msgpack::zone const& zone() const { return *m_zone; } msgpack::zone& zone() { return *m_zone; } void set_zone(msgpack::zone& zone) { m_zone = &zone; } @@ -76,11 +151,15 @@ public: void set_referenced(bool referenced) { m_referenced = referenced; } unpack_reference_func reference_func() const { return m_func; } void* user_data() const { return m_user_data; } + unpack_limit const& limit() const { return m_limit; } + unpack_limit& limit() { return m_limit; } + private: msgpack::zone* m_zone; bool m_referenced; unpack_reference_func m_func; void* m_user_data; + unpack_limit m_limit; }; inline void unpack_uint8(uint8_t d, object& o) @@ -128,6 +207,7 @@ inline void unpack_false(object& o) struct unpack_array { void operator()(unpack_user& u, uint32_t n, object& o) const { + if (n > u.limit().array()) throw array_size_overflow(); o.type = type::ARRAY; o.via.array.size = 0; o.via.array.ptr = static_cast(u.zone().allocate_align(n*sizeof(object))); @@ -145,6 +225,7 @@ inline void unpack_array_item(object& c, object const& o) struct unpack_map { void operator()(unpack_user& u, uint32_t n, object& o) const { + if (n > u.limit().map()) throw map_size_overflow(); o.type = type::MAP; o.via.map.size = 0; o.via.map.ptr = static_cast(u.zone().allocate_align(n*sizeof(object_kv))); @@ -171,6 +252,7 @@ inline void unpack_str(unpack_user& u, const char* p, uint32_t l, object& o) u.set_referenced(true); } else { + if (l > u.limit().str()) throw str_size_overflow(); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.str.ptr = tmp; @@ -186,6 +268,7 @@ inline void unpack_bin(unpack_user& u, const char* p, uint32_t l, object& o) u.set_referenced(true); } else { + if (l > u.limit().bin()) throw bin_size_overflow(); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.bin.ptr = tmp; @@ -193,7 +276,7 @@ inline void unpack_bin(unpack_user& u, const char* p, uint32_t l, object& o) o.via.bin.size = l; } -inline void unpack_ext(unpack_user& u, const char* p, uint32_t l, object& o) +inline void unpack_ext(unpack_user& u, const char* p, std::size_t l, object& o) { o.type = type::EXT; if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { @@ -201,6 +284,7 @@ inline void unpack_ext(unpack_user& u, const char* p, uint32_t l, object& o) u.set_referenced(true); } else { + if (l > u.limit().ext()) throw ext_size_overflow(); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.ext.ptr = tmp; @@ -290,7 +374,8 @@ inline void load(T& dst, const char* n, typename msgpack::enable_if= off); - - m_start = data; - m_current = data + off; - m_stack_idx = 0; - const char* const pe = data + len; - const char* n = nullptr; - - object obj; - - if(m_current == pe) { - off = m_current - m_start; - return 0; - } - bool fixed_trail_again = false; - do { - if (m_cs == CS_HEADER) { - fixed_trail_again = false; - int selector = *reinterpret_cast(m_current); - if (0x00 <= selector && selector <= 0x7f) { // Positive Fixnum - unpack_uint8(*reinterpret_cast(m_current), obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } else if(0xe0 <= selector && selector <= 0xff) { // Negative Fixnum - unpack_int8(*reinterpret_cast(m_current), obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } else if (0xc4 <= selector && selector <= 0xdf) { - const uint32_t trail[] = { - 1, // bin 8 0xc4 - 2, // bin 16 0xc5 - 4, // bin 32 0xc6 - 1, // ext 8 0xc7 - 2, // ext 16 0xc8 - 4, // ext 32 0xc9 - 4, // float 32 0xca - 8, // float 64 0xcb - 1, // uint 8 0xcc - 2, // uint 16 0xcd - 4, // uint 32 0xce - 8, // uint 64 0xcf - 1, // int 8 0xd0 - 2, // int 16 0xd1 - 4, // int 32 0xd2 - 8, // int 64 0xd3 - 2, // fixext 1 0xd4 - 3, // fixext 2 0xd5 - 5, // fixext 4 0xd6 - 9, // fixext 8 0xd7 - 17,// fixext 16 0xd8 - 1, // str 8 0xd9 - 2, // str 16 0xda - 4, // str 32 0xdb - 2, // array 16 0xdc - 4, // array 32 0xdd - 2, // map 16 0xde - 4, // map 32 0xdf - }; - m_trail = trail[selector - 0xc4]; - m_cs = next_cs(m_current); - fixed_trail_again = true; - } else if(0xa0 <= selector && selector <= 0xbf) { // FixStr - m_trail = static_cast(*m_current) & 0x1f; - if(m_trail == 0) { - unpack_str(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_STR_VALUE; - fixed_trail_again = true; - } - - } else if(0x90 <= selector && selector <= 0x9f) { // FixArray - int ret = push_aggregate( - unpack_array(), CT_ARRAY_ITEM, obj, m_current, off); - if (ret != 0) return ret; - } else if(0x80 <= selector && selector <= 0x8f) { // FixMap - int ret = push_aggregate( - unpack_map(), CT_MAP_KEY, obj, m_current, off); - if (ret != 0) return ret; - } else if(selector == 0xc2) { // false - unpack_false(obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } else if(selector == 0xc3) { // true - unpack_true(obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } else if(selector == 0xc0) { // nil - unpack_nil(obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } else { - off = m_current - m_start; - return -1; - } - // end CS_HEADER - } - if (m_cs != CS_HEADER || fixed_trail_again) { - if (fixed_trail_again) { - ++m_current; - fixed_trail_again = false; - } - if(static_cast(pe - m_current) < m_trail) { - off = m_current - m_start; - return 0; - } - n = m_current; - m_current += m_trail - 1; - switch(m_cs) { - //case CS_ - //case CS_ - case CS_FLOAT: { - union { uint32_t i; float f; } mem; - load(mem.i, n); - unpack_float(mem.f, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_DOUBLE: { - union { uint64_t i; double f; } mem; - load(mem.i, n); -#if defined(__arm__) && !(__ARM_EABI__) // arm-oabi - // https://github.com/msgpack/msgpack-perl/pull/1 - mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL); -#endif - unpack_double(mem.f, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_UINT_8: { - uint8_t tmp; - load(tmp, n); - unpack_uint8(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_UINT_16: { - uint16_t tmp; - load(tmp, n); - unpack_uint16(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_UINT_32: { - uint32_t tmp; - load(tmp, n); - unpack_uint32(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_UINT_64: { - uint64_t tmp; - load(tmp, n); - unpack_uint64(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_INT_8: { - int8_t tmp; - load(tmp, n); - unpack_int8(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_INT_16: { - int16_t tmp; - load(tmp, n); - unpack_int16(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_INT_32: { - int32_t tmp; - load(tmp, n); - unpack_int32(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_INT_64: { - int64_t tmp; - load(tmp, n); - unpack_int64(tmp, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_FIXEXT_1: { - unpack_ext(m_user, n, 1+1, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_FIXEXT_2: { - unpack_ext(m_user, n, 2+1, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_FIXEXT_4: { - unpack_ext(m_user, n, 4+1, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_FIXEXT_8: { - unpack_ext(m_user, n, 8+1, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_FIXEXT_16: { - unpack_ext(m_user, n, 16+1, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_STR_8: { - uint8_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_str(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_STR_VALUE; - fixed_trail_again = true; - } - } break; - case CS_BIN_8: { - uint8_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_bin(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_BIN_VALUE; - fixed_trail_again = true; - } - } break; - case CS_EXT_8: { - uint8_t tmp; - load(tmp, n); - m_trail = tmp + 1; - if(m_trail == 0) { - unpack_ext(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_EXT_VALUE; - fixed_trail_again = true; - } - } break; - case CS_STR_16: { - uint16_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_str(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_STR_VALUE; - fixed_trail_again = true; - } - } break; - case CS_BIN_16: { - uint16_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_bin(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_BIN_VALUE; - fixed_trail_again = true; - } - } break; - case CS_EXT_16: { - uint16_t tmp; - load(tmp, n); - m_trail = tmp + 1; - if(m_trail == 0) { - unpack_ext(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_EXT_VALUE; - fixed_trail_again = true; - } - } break; - case CS_STR_32: { - uint32_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_str(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_STR_VALUE; - fixed_trail_again = true; - } - } break; - case CS_BIN_32: { - uint32_t tmp; - load(tmp, n); - m_trail = tmp; - if(m_trail == 0) { - unpack_bin(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_BIN_VALUE; - fixed_trail_again = true; - } - } break; - case CS_EXT_32: { - uint32_t tmp; - load(tmp, n); - m_trail = tmp + 1; - if(m_trail == 0) { - unpack_ext(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } - else { - m_cs = ACS_EXT_VALUE; - fixed_trail_again = true; - } - } break; - case ACS_STR_VALUE: { - unpack_str(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case ACS_BIN_VALUE: { - unpack_bin(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case ACS_EXT_VALUE: { - unpack_ext(m_user, n, m_trail, obj); - int ret = push_proc(obj, off); - if (ret != 0) return ret; - } break; - case CS_ARRAY_16: { - int ret = push_aggregate( - unpack_array(), CT_ARRAY_ITEM, obj, n, off); - if (ret != 0) return ret; - } break; - case CS_ARRAY_32: { - /* FIXME security guard */ - int ret = push_aggregate( - unpack_array(), CT_ARRAY_ITEM, obj, n, off); - if (ret != 0) return ret; - } break; - case CS_MAP_16: { - int ret = push_aggregate( - unpack_map(), CT_MAP_KEY, obj, n, off); - if (ret != 0) return ret; - } break; - case CS_MAP_32: { - /* FIXME security guard */ - int ret = push_aggregate( - unpack_map(), CT_MAP_KEY, obj, n, off); - if (ret != 0) return ret; - } break; - default: - off = m_current - m_start; - return -1; - } - } - } while(m_current != pe); - - off = m_current - m_start; - return 0; - } + int execute(const char* data, std::size_t len, std::size_t& off); private: template @@ -806,11 +505,15 @@ private: return ret; } + template + static void check_ext_size(std::size_t size) { + } + private: char const* m_start; char const* m_current; - uint32_t m_trail; + std::size_t m_trail; unpack_user m_user; uint32_t m_cs; uint32_t m_top; @@ -818,18 +521,402 @@ private: unpack_stack m_stack[MSGPACK_EMBED_STACK_SIZE]; }; -} // detail +template <> +inline void context::check_ext_size<4>(std::size_t size) { + if (size == 0xffffffff) throw ext_size_overflow(); +} +inline int context::execute(const char* data, std::size_t len, std::size_t& off) +{ + assert(len >= off); -struct unpack_error : public std::runtime_error { -#if defined(MSGPACK_USE_CPP03) - unpack_error(const std::string& msg) : - std::runtime_error(msg) { } -#else - unpack_error(const char* msg) : - std::runtime_error(msg) { } + m_start = data; + m_current = data + off; + m_stack_idx = 0; + const char* const pe = data + len; + const char* n = nullptr; + + object obj; + + if(m_current == pe) { + off = m_current - m_start; + return 0; + } + bool fixed_trail_again = false; + do { + if (m_cs == CS_HEADER) { + fixed_trail_again = false; + int selector = *reinterpret_cast(m_current); + if (0x00 <= selector && selector <= 0x7f) { // Positive Fixnum + unpack_uint8(*reinterpret_cast(m_current), obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } else if(0xe0 <= selector && selector <= 0xff) { // Negative Fixnum + unpack_int8(*reinterpret_cast(m_current), obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } else if (0xc4 <= selector && selector <= 0xdf) { + const uint32_t trail[] = { + 1, // bin 8 0xc4 + 2, // bin 16 0xc5 + 4, // bin 32 0xc6 + 1, // ext 8 0xc7 + 2, // ext 16 0xc8 + 4, // ext 32 0xc9 + 4, // float 32 0xca + 8, // float 64 0xcb + 1, // uint 8 0xcc + 2, // uint 16 0xcd + 4, // uint 32 0xce + 8, // uint 64 0xcf + 1, // int 8 0xd0 + 2, // int 16 0xd1 + 4, // int 32 0xd2 + 8, // int 64 0xd3 + 2, // fixext 1 0xd4 + 3, // fixext 2 0xd5 + 5, // fixext 4 0xd6 + 9, // fixext 8 0xd7 + 17,// fixext 16 0xd8 + 1, // str 8 0xd9 + 2, // str 16 0xda + 4, // str 32 0xdb + 2, // array 16 0xdc + 4, // array 32 0xdd + 2, // map 16 0xde + 4, // map 32 0xdf + }; + m_trail = trail[selector - 0xc4]; + m_cs = next_cs(m_current); + fixed_trail_again = true; + } else if(0xa0 <= selector && selector <= 0xbf) { // FixStr + m_trail = static_cast(*m_current) & 0x1f; + if(m_trail == 0) { + unpack_str(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_STR_VALUE; + fixed_trail_again = true; + } + + } else if(0x90 <= selector && selector <= 0x9f) { // FixArray + int ret = push_aggregate( + unpack_array(), CT_ARRAY_ITEM, obj, m_current, off); + if (ret != 0) return ret; + } else if(0x80 <= selector && selector <= 0x8f) { // FixMap + int ret = push_aggregate( + unpack_map(), CT_MAP_KEY, obj, m_current, off); + if (ret != 0) return ret; + } else if(selector == 0xc2) { // false + unpack_false(obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } else if(selector == 0xc3) { // true + unpack_true(obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } else if(selector == 0xc0) { // nil + unpack_nil(obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } else { + off = m_current - m_start; + return -1; + } + // end CS_HEADER + } + if (m_cs != CS_HEADER || fixed_trail_again) { + if (fixed_trail_again) { + ++m_current; + fixed_trail_again = false; + } + if(static_cast(pe - m_current) < m_trail) { + off = m_current - m_start; + return 0; + } + n = m_current; + m_current += m_trail - 1; + switch(m_cs) { + //case CS_ + //case CS_ + case CS_FLOAT: { + union { uint32_t i; float f; } mem; + load(mem.i, n); + unpack_float(mem.f, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_DOUBLE: { + union { uint64_t i; double f; } mem; + load(mem.i, n); +#if defined(__arm__) && !(__ARM_EABI__) // arm-oabi + // https://github.com/msgpack/msgpack-perl/pull/1 + mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL); #endif -}; + unpack_double(mem.f, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_UINT_8: { + uint8_t tmp; + load(tmp, n); + unpack_uint8(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_UINT_16: { + uint16_t tmp; + load(tmp, n); + unpack_uint16(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_UINT_32: { + uint32_t tmp; + load(tmp, n); + unpack_uint32(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_UINT_64: { + uint64_t tmp; + load(tmp, n); + unpack_uint64(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_INT_8: { + int8_t tmp; + load(tmp, n); + unpack_int8(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_INT_16: { + int16_t tmp; + load(tmp, n); + unpack_int16(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_INT_32: { + int32_t tmp; + load(tmp, n); + unpack_int32(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_INT_64: { + int64_t tmp; + load(tmp, n); + unpack_int64(tmp, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_1: { + unpack_ext(m_user, n, 1+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_2: { + unpack_ext(m_user, n, 2+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_4: { + unpack_ext(m_user, n, 4+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_8: { + unpack_ext(m_user, n, 8+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_16: { + unpack_ext(m_user, n, 16+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_STR_8: { + uint8_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_str(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_STR_VALUE; + fixed_trail_again = true; + } + } break; + case CS_BIN_8: { + uint8_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_bin(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_BIN_VALUE; + fixed_trail_again = true; + } + } break; + case CS_EXT_8: { + uint8_t tmp; + load(tmp, n); + m_trail = tmp + 1; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; + case CS_STR_16: { + uint16_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_str(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_STR_VALUE; + fixed_trail_again = true; + } + } break; + case CS_BIN_16: { + uint16_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_bin(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_BIN_VALUE; + fixed_trail_again = true; + } + } break; + case CS_EXT_16: { + uint16_t tmp; + load(tmp, n); + m_trail = tmp + 1; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; + case CS_STR_32: { + uint32_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_str(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_STR_VALUE; + fixed_trail_again = true; + } + } break; + case CS_BIN_32: { + uint32_t tmp; + load(tmp, n); + m_trail = tmp; + if(m_trail == 0) { + unpack_bin(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_BIN_VALUE; + fixed_trail_again = true; + } + } break; + case CS_EXT_32: { + uint32_t tmp; + load(tmp, n); + check_ext_size(tmp); + m_trail = tmp; + ++m_trail; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; + case ACS_STR_VALUE: { + unpack_str(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case ACS_BIN_VALUE: { + unpack_bin(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case ACS_EXT_VALUE: { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_ARRAY_16: { + int ret = push_aggregate( + unpack_array(), CT_ARRAY_ITEM, obj, n, off); + if (ret != 0) return ret; + } break; + case CS_ARRAY_32: { + /* FIXME security guard */ + int ret = push_aggregate( + unpack_array(), CT_ARRAY_ITEM, obj, n, off); + if (ret != 0) return ret; + } break; + case CS_MAP_16: { + int ret = push_aggregate( + unpack_map(), CT_MAP_KEY, obj, n, off); + if (ret != 0) return ret; + } break; + case CS_MAP_32: { + /* FIXME security guard */ + int ret = push_aggregate( + unpack_map(), CT_MAP_KEY, obj, n, off); + if (ret != 0) return ret; + } break; + default: + off = m_current - m_start; + return -1; + } + } + } while(m_current != pe); + + off = m_current - m_start; + return 0; +} + +} // detail class unpacked { @@ -861,7 +948,8 @@ class unpacker { public: unpacker(unpack_reference_func f = &unpacker::default_reference_func, void* user_data = nullptr, - std::size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE); + std::size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE, + unpack_limit const& limit = unpack_limit()); #if !defined(MSGPACK_USE_CPP03) unpacker(unpacker&& other); @@ -987,37 +1075,47 @@ private: inline unpacked unpack( const char* data, std::size_t len, std::size_t& off, bool& referenced, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); inline unpacked unpack( const char* data, std::size_t len, std::size_t& off, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); inline unpacked unpack( const char* data, std::size_t len, bool& referenced, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); inline unpacked unpack( const char* data, std::size_t len, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); #endif // !defined(MSGPACK_USE_CPP03) inline void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, bool& referenced, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); inline void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); inline void unpack(unpacked& result, const char* data, std::size_t len, bool& referenced, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); + inline void unpack(unpacked& result, const char* data, std::size_t len, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); // obsolete inline void unpack(unpacked* result, const char* data, std::size_t len, std::size_t* off = nullptr, bool* referenced = nullptr, - unpack_reference_func f = nullptr, void* user_data = nullptr); + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()); // for internal use @@ -1030,8 +1128,9 @@ typedef enum { inline unpacker::unpacker(unpack_reference_func f, void* user_data, - std::size_t initial_buffer_size) - :m_z(new zone), m_ctx(f, user_data) + std::size_t initial_buffer_size, + unpack_limit const& limit) + :m_z(new zone), m_ctx(f, user_data, limit) { if(initial_buffer_size < COUNTER_SIZE) { initial_buffer_size = COUNTER_SIZE; @@ -1181,7 +1280,7 @@ inline bool unpacker::next(unpacked& result, bool& referenced) referenced = false; int ret = execute_imp(); if(ret < 0) { - throw unpack_error("parse error"); + throw parse_error(); } if(ret == 0) { @@ -1214,7 +1313,7 @@ inline bool unpacker::execute() { int ret = execute_imp(); if(ret < 0) { - throw unpack_error("parse error"); + throw parse_error(); } else if(ret == 0) { return false; } else { @@ -1314,7 +1413,8 @@ namespace detail { inline unpack_return unpack_imp(const char* data, std::size_t len, std::size_t& off, zone& result_zone, object& result, bool& referenced, - unpack_reference_func f = nullptr, void* user_data = nullptr) + unpack_reference_func f = nullptr, void* user_data = nullptr, + unpack_limit const& limit = unpack_limit()) { std::size_t noff = off; @@ -1323,7 +1423,7 @@ unpack_imp(const char* data, std::size_t len, std::size_t& off, return UNPACK_CONTINUE; } - detail::context ctx(f, user_data); + detail::context ctx(f, user_data, limit); ctx.init(); ctx.user().set_zone(result_zone); @@ -1359,13 +1459,13 @@ unpack_imp(const char* data, std::size_t len, std::size_t& off, inline unpacked unpack( const char* data, std::size_t len, std::size_t& off, bool& referenced, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { object obj; msgpack::unique_ptr z(new zone); referenced = false; unpack_return ret = detail::unpack_imp( - data, len, off, *z, obj, referenced, f, user_data); + data, len, off, *z, obj, referenced, f, user_data, limit); switch(ret) { case UNPACK_SUCCESS: @@ -1373,37 +1473,37 @@ inline unpacked unpack( case UNPACK_EXTRA_BYTES: return unpacked(obj, msgpack::move(z)); case UNPACK_CONTINUE: - throw unpack_error("insufficient bytes"); + throw insufficient_bytes(); case UNPACK_PARSE_ERROR: default: - throw unpack_error("parse error"); + throw parse_error(); } return unpacked(); } inline unpacked unpack( const char* data, std::size_t len, std::size_t& off, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { bool referenced; - return unpack(data, len, off, referenced, f, user_data); + return unpack(data, len, off, referenced, f, user_data, limit); } inline unpacked unpack( const char* data, std::size_t len, bool& referenced, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { std::size_t off = 0; - return unpack(data, len, off, referenced, f, user_data); + return unpack(data, len, off, referenced, f, user_data, limit); } inline unpacked unpack( const char* data, std::size_t len, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { bool referenced; std::size_t off = 0; - return unpack(data, len, off, referenced, f, user_data); + return unpack(data, len, off, referenced, f, user_data, limit); } #endif // !defined(MSGPACK_USE_CPP03) @@ -1411,13 +1511,13 @@ inline unpacked unpack( inline void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, bool& referenced, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { object obj; msgpack::unique_ptr z(new zone); referenced = false; unpack_return ret = detail::unpack_imp( - data, len, off, *z, obj, referenced, f, user_data); + data, len, off, *z, obj, referenced, f, user_data, limit); switch(ret) { case UNPACK_SUCCESS: @@ -1429,50 +1529,50 @@ inline void unpack(unpacked& result, result.zone() = msgpack::move(z); return; case UNPACK_CONTINUE: - throw unpack_error("insufficient bytes"); + throw insufficient_bytes(); case UNPACK_PARSE_ERROR: default: - throw unpack_error("parse error"); + throw parse_error(); } } inline void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { bool referenced; - unpack(result, data, len, off, referenced, f, user_data); + unpack(result, data, len, off, referenced, f, user_data, limit); } inline void unpack(unpacked& result, const char* data, std::size_t len, bool& referenced, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { std::size_t off = 0; - unpack(result, data, len, off, referenced, f, user_data); + unpack(result, data, len, off, referenced, f, user_data, limit); } inline void unpack(unpacked& result, const char* data, std::size_t len, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { bool referenced; std::size_t off = 0; - unpack(result, data, len, off, referenced, f, user_data); + unpack(result, data, len, off, referenced, f, user_data, limit); } // obsolete // pointer version inline void unpack(unpacked* result, const char* data, std::size_t len, std::size_t* off, bool* referenced, - unpack_reference_func f, void* user_data) + unpack_reference_func f, void* user_data, unpack_limit const& limit) { if (off) - if (referenced) unpack(*result, data, len, *off, *referenced, f, user_data); - else unpack(*result, data, len, *off, f, user_data); + if (referenced) unpack(*result, data, len, *off, *referenced, f, user_data, limit); + else unpack(*result, data, len, *off, f, user_data, limit); else - if (referenced) unpack(*result, data, len, *referenced, f, user_data); - else unpack(*result, data, len, f, user_data); + if (referenced) unpack(*result, data, len, *referenced, f, user_data, limit); + else unpack(*result, data, len, f, user_data, limit); } inline bool unpacker::default_reference_func(type::object_type /*type*/, std::size_t /*len*/, void*) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 028f8be8..3642ef1b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,6 +28,7 @@ LIST (APPEND check_PROGRAMS msgpack_vref.cpp msgpack_c.cpp reference.cpp + limit.cpp ) IF (MSGPACK_CXX11) diff --git a/test/Makefile.am b/test/Makefile.am index c12c56d2..6979a3ba 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,7 +24,8 @@ check_PROGRAMS = \ msgpack_vref \ msgpack_cpp11 \ reference_cpp11 \ - reference + reference \ + limit TESTS = $(check_PROGRAMS) @@ -73,4 +74,6 @@ reference_SOURCES = reference.cpp reference_cpp11_SOURCES = reference_cpp11.cpp +limit_SOURCES = limit.cpp + EXTRA_DIST = cases.mpac cases_compact.mpac diff --git a/test/limit.cpp b/test/limit.cpp new file mode 100644 index 00000000..2a5f1a61 --- /dev/null +++ b/test/limit.cpp @@ -0,0 +1,509 @@ +#include +#include +#include + +TEST(limit, unpack_array_no_over) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(3, 0, 0, 0, 0)); + EXPECT_TRUE(true); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_map_no_over) +{ + std::stringstream ss; + std::map m; + m[1] = 1; + m[2] = 2; + m[3] = 3; + msgpack::pack(ss, m); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 3, 0, 0, 0)); + EXPECT_TRUE(true); + } + catch(msgpack::map_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_map_over) +{ + std::stringstream ss; + std::map m; + m[1] = 1; + m[2] = 2; + m[3] = 3; + msgpack::pack(ss, m); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 2, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::map_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_str_no_over) +{ + std::stringstream ss; + std::string s("123"); + msgpack::pack(ss, s); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 3, 0, 0)); + EXPECT_TRUE(true); + } + catch(msgpack::str_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_str_over) +{ + std::stringstream ss; + std::string s("123"); + msgpack::pack(ss, s); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 2, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::str_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_bin_no_over) +{ + std::stringstream ss; + std::vector v; + v.push_back('1'); + v.push_back('2'); + v.push_back('3'); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 3, 0)); + EXPECT_TRUE(true); + } + catch(msgpack::bin_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_bin_over) +{ + std::stringstream ss; + std::vector v; + v.push_back('1'); + v.push_back('2'); + v.push_back('3'); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 2, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::bin_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_ext_no_over) +{ + std::stringstream ss; + msgpack::packer packer(ss); + char const buf [] = { 1, 2, 3 }; + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 0, 3+1)); + EXPECT_TRUE(true); + } + catch(msgpack::ext_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_ext_over) +{ + std::stringstream ss; + msgpack::packer packer(ss); + char const buf [] = { 1, 2, 3 }; + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 0, 2+1)); + EXPECT_TRUE(false); + } + catch(msgpack::ext_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_ext_over_32_bit) +{ + if (sizeof(std::size_t) == 4) { + char const buf [] = { + static_cast(0xc9), + static_cast(0xff), + static_cast(0xff), + static_cast(0xff), + static_cast(0xff), + static_cast(0x01), + }; + try { + msgpack::unpacked unp; + msgpack::unpack(unp, buf, sizeof(buf), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 0, 0xffffffff)); + EXPECT_TRUE(false); + } + catch(msgpack::ext_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } + } +} + +TEST(limit, unpack_ext_no_over_64_bit) +{ + if (sizeof(std::size_t) == 8) { + char const buf [] = { + static_cast(0xc9), + static_cast(0xff), + static_cast(0xff), + static_cast(0xff), + static_cast(0xff), + static_cast(0x01), + }; + try { + msgpack::unpacked unp; + msgpack::unpack(unp, buf, sizeof(buf), nullptr, nullptr, + msgpack::unpack_limit(0, 0, 0, 0, 0xffffffff)); + EXPECT_TRUE(false); + } + catch(msgpack::ext_size_overflow const&) { + EXPECT_TRUE(false); + } + catch(msgpack::insufficient_bytes const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } + } +} + +#if !defined(MSGPACK_USE_CPP03) + +TEST(limit, unpack_array_over_cpp11_no_off_no_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp = + msgpack::unpack(ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_cpp11_no_off_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + bool ref; + msgpack::unpacked unp = + msgpack::unpack(ss.str().c_str(), ss.str().size(), ref, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_cpp11_off_no_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + std::size_t off = 0; + msgpack::unpacked unp = + msgpack::unpack(ss.str().c_str(), ss.str().size(), off, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_cpp11_off_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + bool ref; + std::size_t off = 0; + msgpack::unpacked unp = + msgpack::unpack(ss.str().c_str(), ss.str().size(), off, ref, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +#endif // !defined(MSGPACK_USE_CPP03) + +TEST(limit, unpack_array_over_no_off_no_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_no_off_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + bool ref; + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), ref, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_off_no_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + std::size_t off = 0; + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), off, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpack_array_over_off_ref) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + bool ref; + std::size_t off = 0; + msgpack::unpacked unp; + msgpack::unpack(unp, ss.str().c_str(), ss.str().size(), off, ref, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +// obsolete +TEST(limit, unpack_array_over_off_ref_pointer) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + bool ref; + std::size_t off = 0; + msgpack::unpacked unp; + msgpack::unpack(&unp, ss.str().c_str(), ss.str().size(), &off, &ref, nullptr, nullptr, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} + +TEST(limit, unpacker_array_over) +{ + std::stringstream ss; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::pack(ss, v); + try { + msgpack::unpacker u(nullptr, nullptr, MSGPACK_UNPACKER_INIT_BUFFER_SIZE, + msgpack::unpack_limit(2, 0, 0, 0, 0)); + u.reserve_buffer(ss.str().size()); + memcpy(u.buffer(), ss.str().c_str(), ss.str().size()); + u.buffer_consumed(ss.str().size()); + msgpack::unpacked unp; + u.next(unp); + EXPECT_TRUE(false); + } + catch(msgpack::array_size_overflow const&) { + EXPECT_TRUE(true); + } + catch(...) { + EXPECT_TRUE(false); + } +} From 469040be6b51fb61d38420292e6962cf56175f6e Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Mon, 15 Dec 2014 10:12:55 +0900 Subject: [PATCH 2/2] Fixed exceptions' interface. On the C++11, both const char* and const std::string& are supported. Updated all exceptions relate to unpack take a message parameter. It is better to explain the exceptional situation in detail. So far, just passing the exceptions name. --- include/msgpack/unpack.hpp | 95 ++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/include/msgpack/unpack.hpp b/include/msgpack/unpack.hpp index 042e4e6f..8d3f26d9 100644 --- a/include/msgpack/unpack.hpp +++ b/include/msgpack/unpack.hpp @@ -64,49 +64,84 @@ MSGPACK_API_VERSION_NAMESPACE(v1) { typedef bool (*unpack_reference_func)(type::object_type, std::size_t, void*); struct unpack_error : public std::runtime_error { -#if defined(MSGPACK_USE_CPP03) - unpack_error(const std::string& msg) : - std::runtime_error(msg) { } -#else - unpack_error(const char* msg) : - std::runtime_error(msg) { } -#endif + explicit unpack_error(const std::string& msg) + :std::runtime_error(msg) {} +#if !defined(MSGPACK_USE_CPP03) + explicit unpack_error(const char* msg): + std::runtime_error(msg) {} +#endif // !defined(MSGPACK_USE_CPP03) }; struct parse_error : public unpack_error { - parse_error():unpack_error("parse error") {} + explicit parse_error(const std::string& msg) + :unpack_error(msg) {} +#if !defined(MSGPACK_USE_CPP03) + explicit parse_error(const char* msg) + :unpack_error(msg) {} +#endif // !defined(MSGPACK_USE_CPP03) }; struct insufficient_bytes : public unpack_error { - insufficient_bytes():unpack_error("insufficient bytes") {} + explicit insufficient_bytes(const std::string& msg) + :unpack_error(msg) {} +#if !defined(MSGPACK_USE_CPP03) + explicit insufficient_bytes(const char* msg) + :unpack_error(msg) {} +#endif // !defined(MSGPACK_USE_CPP03) }; struct size_overflow : public unpack_error { -#if defined(MSGPACK_USE_CPP03) - size_overflow(const std::string& msg):unpack_error(msg) {} -#else - size_overflow(const char* msg):unpack_error(msg) {} + explicit size_overflow(const std::string& msg) + :unpack_error(msg) {} +#if !defined(MSGPACK_USE_CPP03) + explicit size_overflow(const char* msg) + :unpack_error(msg) {} #endif }; struct array_size_overflow : public size_overflow { - array_size_overflow():size_overflow("array size overflow") {} + array_size_overflow(const std::string& msg) + :size_overflow(msg) {} +#if !defined(MSGPACK_USE_CPP03) + array_size_overflow(const char* msg) + :size_overflow(msg) {} +#endif }; struct map_size_overflow : public size_overflow { - map_size_overflow():size_overflow("map size overflow") {} + map_size_overflow(const std::string& msg) + :size_overflow(msg) {} +#if !defined(MSGPACK_USE_CPP03) + map_size_overflow(const char* msg) + :size_overflow(msg) {} +#endif }; struct str_size_overflow : public size_overflow { - str_size_overflow():size_overflow("str size overflow") {} + str_size_overflow(const std::string& msg) + :size_overflow(msg) {} +#if !defined(MSGPACK_USE_CPP03) + str_size_overflow(const char* msg) + :size_overflow(msg) {} +#endif }; struct bin_size_overflow : public size_overflow { - bin_size_overflow():size_overflow("bin size overflow") {} + bin_size_overflow(const std::string& msg) + :size_overflow(msg) {} +#if !defined(MSGPACK_USE_CPP03) + bin_size_overflow(const char* msg) + :size_overflow(msg) {} +#endif }; struct ext_size_overflow : public size_overflow { - ext_size_overflow():size_overflow("ext size overflow") {} + ext_size_overflow(const std::string& msg) + :size_overflow(msg) {} +#if !defined(MSGPACK_USE_CPP03) + ext_size_overflow(const char* msg) + :size_overflow(msg) {} +#endif }; class unpack_limit { @@ -207,7 +242,7 @@ inline void unpack_false(object& o) struct unpack_array { void operator()(unpack_user& u, uint32_t n, object& o) const { - if (n > u.limit().array()) throw array_size_overflow(); + if (n > u.limit().array()) throw array_size_overflow("array size overflow"); o.type = type::ARRAY; o.via.array.size = 0; o.via.array.ptr = static_cast(u.zone().allocate_align(n*sizeof(object))); @@ -225,7 +260,7 @@ inline void unpack_array_item(object& c, object const& o) struct unpack_map { void operator()(unpack_user& u, uint32_t n, object& o) const { - if (n > u.limit().map()) throw map_size_overflow(); + if (n > u.limit().map()) throw map_size_overflow("map size overflow"); o.type = type::MAP; o.via.map.size = 0; o.via.map.ptr = static_cast(u.zone().allocate_align(n*sizeof(object_kv))); @@ -252,7 +287,7 @@ inline void unpack_str(unpack_user& u, const char* p, uint32_t l, object& o) u.set_referenced(true); } else { - if (l > u.limit().str()) throw str_size_overflow(); + if (l > u.limit().str()) throw str_size_overflow("str size overflow"); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.str.ptr = tmp; @@ -268,7 +303,7 @@ inline void unpack_bin(unpack_user& u, const char* p, uint32_t l, object& o) u.set_referenced(true); } else { - if (l > u.limit().bin()) throw bin_size_overflow(); + if (l > u.limit().bin()) throw bin_size_overflow("bin size overflow"); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.bin.ptr = tmp; @@ -284,7 +319,7 @@ inline void unpack_ext(unpack_user& u, const char* p, std::size_t l, object& o) u.set_referenced(true); } else { - if (l > u.limit().ext()) throw ext_size_overflow(); + if (l > u.limit().ext()) throw ext_size_overflow("ext size overflow"); char* tmp = static_cast(u.zone().allocate_align(l)); std::memcpy(tmp, p, l); o.via.ext.ptr = tmp; @@ -523,7 +558,7 @@ private: template <> inline void context::check_ext_size<4>(std::size_t size) { - if (size == 0xffffffff) throw ext_size_overflow(); + if (size == 0xffffffff) throw ext_size_overflow("ext size overflow"); } inline int context::execute(const char* data, std::size_t len, std::size_t& off) @@ -1280,7 +1315,7 @@ inline bool unpacker::next(unpacked& result, bool& referenced) referenced = false; int ret = execute_imp(); if(ret < 0) { - throw parse_error(); + throw parse_error("parse error"); } if(ret == 0) { @@ -1313,7 +1348,7 @@ inline bool unpacker::execute() { int ret = execute_imp(); if(ret < 0) { - throw parse_error(); + throw parse_error("parse error"); } else if(ret == 0) { return false; } else { @@ -1473,10 +1508,10 @@ inline unpacked unpack( case UNPACK_EXTRA_BYTES: return unpacked(obj, msgpack::move(z)); case UNPACK_CONTINUE: - throw insufficient_bytes(); + throw insufficient_bytes("insufficient bytes"); case UNPACK_PARSE_ERROR: default: - throw parse_error(); + throw parse_error("parse error"); } return unpacked(); } @@ -1529,10 +1564,10 @@ inline void unpack(unpacked& result, result.zone() = msgpack::move(z); return; case UNPACK_CONTINUE: - throw insufficient_bytes(); + throw insufficient_bytes("insufficient bytes"); case UNPACK_PARSE_ERROR: default: - throw parse_error(); + throw parse_error("parse error"); } }