diff --git a/src/dict.c b/src/dict.c index 69ea252550..5a75bd78d6 100644 --- a/src/dict.c +++ b/src/dict.c @@ -35,6 +35,7 @@ #include "fmacros.h" +#include #include #include #include @@ -48,6 +49,10 @@ #include "serverassert.h" #include "monotonic.h" +#ifndef static_assert +#define static_assert(expr, lit) extern char __static_assert_failure[(expr) ? 1 : -1] +#endif + /* Using dictSetResizeEnabled() we make possible to disable * resizing and rehashing of the hash table as needed. This is very important * for us, as we use copy-on-write and don't want to move too much memory @@ -74,7 +79,7 @@ struct dictEntry { struct dictEntry *next; /* Next entry in the same hash bucket. */ }; -typedef struct __attribute__((packed)) { +typedef struct { union { void *val; uint64_t u64; @@ -86,11 +91,24 @@ typedef struct __attribute__((packed)) { unsigned char key_buf[]; /* buffer to embed the key. */ } embeddedDictEntry; +static_assert(sizeof(embeddedDictEntry) == 24, "unexpected total size of embeddedDictEntry"); +static_assert(offsetof(embeddedDictEntry, v) == 0, "unexpected field offset"); +static_assert(offsetof(embeddedDictEntry, next) == 8, "unexpected field offset"); +static_assert(offsetof(embeddedDictEntry, key_header_size) == 16, "unexpected field offset"); +static_assert(offsetof(embeddedDictEntry, key_buf) == 17, "unexpected field offset"); + +/* The minimum amount of bytes required for embedded dict entry. */ +static inline size_t compactSizeEmbeddedDictEntry(void) { + return offsetof(embeddedDictEntry, key_buf); +} + typedef struct { void *key; dictEntry *next; } dictEntryNoValue; +/* Helper and validation for `embeddedDictEntry` */ + /* -------------------------- private prototypes ---------------------------- */ static void _dictExpandIfNeeded(dict *d); @@ -182,7 +200,7 @@ static inline dictEntry *createEntryNoValue(void *key, dictEntry *next) { static inline dictEntry *createEmbeddedEntry(void *key, dictEntry *next, dictType *dt) { size_t key_len = dt->embedKey(NULL, 0, key, NULL); - embeddedDictEntry *entry = zmalloc(sizeof(*entry) + key_len); + embeddedDictEntry *entry = zmalloc(compactSizeEmbeddedDictEntry() + key_len); dt->embedKey(entry->key_buf, key_len, key, &entry->key_header_size); entry->next = next; return encodeMaskedPtr(entry, ENTRY_PTR_EMBEDDED);