diff --git a/include/msgpack/zone.h b/include/msgpack/zone.h index 500698f3b..3c27da975 100644 --- a/include/msgpack/zone.h +++ b/include/msgpack/zone.h @@ -125,7 +125,13 @@ static inline void* msgpack_zone_malloc(msgpack_zone* zone, size_t size) { void* ptr = msgpack_zone_malloc_expand(zone, size + (MSGPACK_ZONE_ALIGN - 1)); if (ptr) { - return (char*)((uintptr_t)(ptr) & ~(uintptr_t)(MSGPACK_ZONE_ALIGN - 1)); + /* round up into the padding reserved above; rounding down + * would hand out the new chunk's header */ + return (char*)( + (uintptr_t)( + (char*)ptr + (MSGPACK_ZONE_ALIGN - 1) + ) & ~(uintptr_t)(MSGPACK_ZONE_ALIGN - 1) + ); } } return NULL; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c098470a5..583a806ed 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,6 +13,7 @@ SET (check_PROGRAMS msgpack_c.cpp pack_unpack_c.cpp streaming_c.cpp + zone_align_c.cpp zone_c.cpp ) diff --git a/test/zone_align_c.cpp b/test/zone_align_c.cpp new file mode 100644 index 000000000..8f126e8a4 --- /dev/null +++ b/test/zone_align_c.cpp @@ -0,0 +1,29 @@ +/* msgpack_zone_malloc() is inline, so its alignment is fixed per translation + * unit. Use one stricter than the zone chunk header, as CMakeLists.txt does + * on sparc (MSGPACK_ZONE_ALIGN=8 with a 4-byte header), so that an object + * served from a newly expanded chunk needs padding. */ +#undef MSGPACK_ZONE_ALIGN +#define MSGPACK_ZONE_ALIGN (2 * sizeof(void*)) + +#include + +#include + +#include + +TEST(zone, zone_c_malloc_expand_align) +{ + msgpack_zone z; + const size_t size = 4096; + EXPECT_TRUE(msgpack_zone_init(&z, 2048)); + /* larger than the chunk size: served by msgpack_zone_malloc_expand() */ + char* p = (char*)msgpack_zone_malloc(&z, size); + ASSERT_TRUE(p != NULL); + EXPECT_TRUE((uintptr_t)p % MSGPACK_ZONE_ALIGN == 0); + /* the object has to stay inside the size + MSGPACK_ZONE_ALIGN - 1 bytes + * reserved by the expansion, not overlap the new chunk's header */ + ASSERT_TRUE(p >= z.chunk_list.ptr - (size + MSGPACK_ZONE_ALIGN - 1)); + ASSERT_TRUE(p + size <= z.chunk_list.ptr); + memset(p, 0xff, size); + msgpack_zone_destroy(&z); +}