void mpack_reader_set_skip(mpack_reader_t* reader, mpack_reader_skip_t skip) { mpack_assert(reader->size != 0, "cannot use skip function without a writeable buffer!"); #if MPACK_OPTIMIZE_FOR_SIZE MPACK_UNUSED(reader); MPACK_UNUSED(skip); #else reader->skip = skip; #endif }
static void test_node_read_possible() { mpack_node_data_t pool[128]; // test early exit for data that contains impossible node numbers #ifdef MPACK_MALLOC // this is an example of a potential denial-of-service attack against // MessagePack implementations that allocate storage up-front. this // should be handled safely without allocating huge amounts of memory. const char* attack = "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff" "\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff\xdd\xff\xff\xff\xff"; size_t allocation_count = test_malloc_count(); mpack_tree_t tree; mpack_tree_init(&tree, attack, strlen(attack)); allocation_count = test_malloc_count() - allocation_count; TEST_TRUE(allocation_count <= 2, "too many allocations! %i calls to malloc()", (int)allocation_count); TEST_TREE_DESTROY_ERROR(&tree, mpack_error_invalid); #endif TEST_SIMPLE_TREE_READ_ERROR("\xcc", (MPACK_UNUSED(node), true), mpack_error_invalid); // truncated u8 TEST_SIMPLE_TREE_READ_ERROR("\xcd", (MPACK_UNUSED(node), true), mpack_error_invalid); // truncated u16 TEST_SIMPLE_TREE_READ_ERROR("\xce", (MPACK_UNUSED(node), true), mpack_error_invalid); // truncated u32 TEST_SIMPLE_TREE_READ_ERROR("\xcf", (MPACK_UNUSED(node), true), mpack_error_invalid); // truncated u64 }
const char* mpack_type_to_string(mpack_type_t type) { #if MPACK_STRINGS switch (type) { #define MPACK_TYPE_STRING_CASE(e) case e: return #e MPACK_TYPE_STRING_CASE(mpack_type_nil); MPACK_TYPE_STRING_CASE(mpack_type_bool); MPACK_TYPE_STRING_CASE(mpack_type_float); MPACK_TYPE_STRING_CASE(mpack_type_double); MPACK_TYPE_STRING_CASE(mpack_type_int); MPACK_TYPE_STRING_CASE(mpack_type_uint); MPACK_TYPE_STRING_CASE(mpack_type_str); MPACK_TYPE_STRING_CASE(mpack_type_bin); MPACK_TYPE_STRING_CASE(mpack_type_ext); MPACK_TYPE_STRING_CASE(mpack_type_array); MPACK_TYPE_STRING_CASE(mpack_type_map); #undef MPACK_TYPE_STRING_CASE default: break; } mpack_assert(0, "unrecognized type %i", (int)type); return "(unknown mpack_type_t)"; #else MPACK_UNUSED(type); return ""; #endif }
mpack_error_t mpack_track_bytes(mpack_track_t* track, bool read, uint64_t count) { MPACK_UNUSED(read); mpack_assert(track->elements, "null track elements!"); if (track->count == 0) { mpack_break("bytes cannot be %s with no open bin, str or ext", read ? "read" : "written"); return mpack_error_bug; } mpack_track_element_t* element = &track->elements[track->count - 1]; if (element->type == mpack_type_map || element->type == mpack_type_array) { mpack_break("bytes cannot be %s within an %s", read ? "read" : "written", mpack_type_to_string(element->type)); return mpack_error_bug; } if (element->left < count) { mpack_break("too many bytes %s for %s", read ? "read" : "written", mpack_type_to_string(element->type)); return mpack_error_bug; } element->left -= count; return mpack_ok; }
void mpack_break_hit(const char* message) { MPACK_UNUSED(message); #if MPACK_STDIO fprintf(stderr, "%s\n", message); #endif #if defined(__GCC__) || defined(__clang__) __builtin_trap(); #elif defined(WIN32) __debugbreak(); #elif MPACK_STDLIB abort(); #elif defined(__GCC__) || defined(__clang__) __builtin_abort(); #endif }
const char* mpack_error_to_string(mpack_error_t error) { #if MPACK_STRINGS switch (error) { #define MPACK_ERROR_STRING_CASE(e) case e: return #e MPACK_ERROR_STRING_CASE(mpack_ok); MPACK_ERROR_STRING_CASE(mpack_error_io); MPACK_ERROR_STRING_CASE(mpack_error_invalid); MPACK_ERROR_STRING_CASE(mpack_error_type); MPACK_ERROR_STRING_CASE(mpack_error_too_big); MPACK_ERROR_STRING_CASE(mpack_error_memory); MPACK_ERROR_STRING_CASE(mpack_error_bug); MPACK_ERROR_STRING_CASE(mpack_error_data); #undef MPACK_ERROR_STRING_CASE default: break; } mpack_assert(0, "unrecognized error %i", (int)error); return "(unknown mpack_error_t)"; #else MPACK_UNUSED(error); return ""; #endif }
mpack_error_t mpack_track_peek_element(mpack_track_t* track, bool read) { MPACK_UNUSED(read); mpack_assert(track->elements, "null track elements!"); // if there are no open elements, that's fine, we can read/write elements at will if (track->count == 0) return mpack_ok; mpack_track_element_t* element = &track->elements[track->count - 1]; if (element->type != mpack_type_map && element->type != mpack_type_array) { mpack_break("elements cannot be %s within an %s", read ? "read" : "written", mpack_type_to_string(element->type)); return mpack_error_bug; } if (element->left == 0) { mpack_break("too many elements %s for %s", read ? "read" : "written", mpack_type_to_string(element->type)); return mpack_error_bug; } return mpack_ok; }