strict aliasing of sized arrays (#1086)
common BUGFIX strict aliasing of sized arrays
The sized array is commonly used for storing an array of pointers or other
structures. Each sized array is preceded by a counter providing the
size of the array. Since we used uint32_t type for the counter, pointers
were misaligned on 64b architectures.
Currently, I don't have any performance measurement, but the sized
arrays are supposed to be used quite intensively in libyang2 and the
strict aliasing could have an impact on the performance. The cost is the
increased size of each array by 4 additional bytes.
The patch changes all the macros working with the counter to use a
generic LY_ARRAY_SIZE_TYPE. For now, it is set to be uint64_t. In the
future it is possible to simply change the type according to the detected
architecture in build time if such a mechanism will make sense.
Fixes #1044
diff --git a/src/tree.h b/src/tree.h
index 32526f4..f2e46ea 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -22,6 +22,11 @@
#endif
/**
+ * @brief Type (i.e. size) of the [sized array](@ref sizedarrays)'s size counter.
+ */
+#define LY_ARRAY_SIZE_TYPE uint64_t
+
+/**
* @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
*/
#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME
@@ -37,7 +42,7 @@
*/
#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
for (ITER = ARRAY; \
- (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((uint32_t*)(ARRAY) - 1)); \
+ (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((LY_ARRAY_SIZE_TYPE*)(ARRAY) - 1)); \
ITER = (void*)((TYPE*)ITER + 1))
/**
@@ -52,7 +57,7 @@
*/
#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
for (INDEX = 0; \
- ARRAY && INDEX < (*((uint32_t*)(ARRAY) - 1)); \
+ ARRAY && INDEX < (*((LY_ARRAY_SIZE_TYPE*)(ARRAY) - 1)); \
++INDEX)
/**
@@ -67,7 +72,7 @@
*
* Does not check if array exists!
*/
-#define LY_ARRAY_SIZE(ARRAY) (*((uint32_t*)(ARRAY) - 1))
+#define LY_ARRAY_SIZE(ARRAY) (*((LY_ARRAY_SIZE_TYPE*)(ARRAY) - 1))
/**
* @brief Sized-array iterator (for-loop).