diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-10-18 05:59:31 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-10-19 11:31:44 +0200 |
commit | 2977904cad8e2da69d03747b88bcbb5a824921e1 (patch) | |
tree | fa978839ecaa648f9588bf6736b17fbbda054c53 | |
parent | macro: paranoia about overflow (diff) | |
download | systemd-2977904cad8e2da69d03747b88bcbb5a824921e1.tar.xz systemd-2977904cad8e2da69d03747b88bcbb5a824921e1.zip |
macro: introduce several helper functions for alignment
Some of them are not used in this commit, but will be used later.
-rw-r--r-- | src/basic/memory-util.h | 9 | ||||
-rw-r--r-- | src/fundamental/macro-fundamental.h | 33 | ||||
-rw-r--r-- | src/test/test-macro.c | 128 | ||||
-rw-r--r-- | src/test/test-memory-util.c | 70 |
4 files changed, 237 insertions, 3 deletions
diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h index b5e3984a09..11795135f9 100644 --- a/src/basic/memory-util.h +++ b/src/basic/memory-util.h @@ -12,9 +12,12 @@ #include "memory-util-fundamental.h" size_t page_size(void) _pure_; -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) -#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1)) -#define PAGE_OFFSET(l) ((l) & (page_size() - 1)) +#define PAGE_ALIGN(l) ALIGN_TO(l, page_size()) +#define PAGE_ALIGN_U64(l) ALIGN_TO_U64(l, page_size()) +#define PAGE_ALIGN_DOWN(l) ALIGN_DOWN(l, page_size()) +#define PAGE_ALIGN_DOWN_U64(l) ALIGN_DOWN_U64(l, page_size()) +#define PAGE_OFFSET(l) ALIGN_OFFSET(l, page_size()) +#define PAGE_OFFSET_U64(l) ALIGN_OFFSET_U64(l, page_size()) /* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */ static inline void *memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index a311b01e30..797330dd97 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -379,6 +379,39 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + (ali - 1)) & ~(ali - 1)); } +static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + if (l > UINT64_MAX - (ali - 1)) + return UINT64_MAX; /* indicate overflow */ + + return ((l + (ali - 1)) & ~(ali - 1)); +} + +static inline size_t ALIGN_DOWN(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline size_t ALIGN_OFFSET(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); +} + +static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); +} + #define ALIGN2(l) ALIGN_TO(l, 2) #define ALIGN4(l) ALIGN_TO(l, 4) #define ALIGN8(l) ALIGN_TO(l, 8) diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 810ebc580e..1b5ef9718e 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -513,6 +513,34 @@ TEST(align_to) { assert_se(ALIGN_TO(SIZE_MAX-1, 4) == SIZE_MAX); /* overflow */ assert_se(ALIGN_TO(SIZE_MAX, 4) == SIZE_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(0, 1) == 0); + assert_se(ALIGN_TO_U64(1, 1) == 1); + assert_se(ALIGN_TO_U64(2, 1) == 2); + assert_se(ALIGN_TO_U64(3, 1) == 3); + assert_se(ALIGN_TO_U64(4, 1) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 1) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX, 1) == UINT64_MAX); + + assert_se(ALIGN_TO_U64(0, 2) == 0); + assert_se(ALIGN_TO_U64(1, 2) == 2); + assert_se(ALIGN_TO_U64(2, 2) == 2); + assert_se(ALIGN_TO_U64(3, 2) == 4); + assert_se(ALIGN_TO_U64(4, 2) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-3, 2) == UINT64_MAX-3); + assert_se(ALIGN_TO_U64(UINT64_MAX-2, 2) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 2) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX, 2) == UINT64_MAX); /* overflow */ + + assert_se(ALIGN_TO_U64(0, 4) == 0); + assert_se(ALIGN_TO_U64(1, 4) == 4); + assert_se(ALIGN_TO_U64(2, 4) == 4); + assert_se(ALIGN_TO_U64(3, 4) == 4); + assert_se(ALIGN_TO_U64(4, 4) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-3, 4) == UINT64_MAX-3); + assert_se(ALIGN_TO_U64(UINT64_MAX-2, 4) == UINT64_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 4) == UINT64_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(UINT64_MAX, 4) == UINT64_MAX); /* overflow */ + assert_cc(CONST_ALIGN_TO(96, 512) == 512); assert_cc(CONST_ALIGN_TO(511, 512) == 512); assert_cc(CONST_ALIGN_TO(512, 512) == 512); @@ -523,6 +551,106 @@ TEST(align_to) { assert_cc(__builtin_types_compatible_p(typeof(CONST_ALIGN_TO(SIZE_MAX, 512)), void)); } +TEST(align_down) { + assert_se(ALIGN_DOWN(0, 1) == 0); + assert_se(ALIGN_DOWN(1, 1) == 1); + assert_se(ALIGN_DOWN(2, 1) == 2); + assert_se(ALIGN_DOWN(3, 1) == 3); + assert_se(ALIGN_DOWN(4, 1) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 1) == SIZE_MAX-1); + assert_se(ALIGN_DOWN(SIZE_MAX, 1) == SIZE_MAX); + + assert_se(ALIGN_DOWN(0, 2) == 0); + assert_se(ALIGN_DOWN(1, 2) == 0); + assert_se(ALIGN_DOWN(2, 2) == 2); + assert_se(ALIGN_DOWN(3, 2) == 2); + assert_se(ALIGN_DOWN(4, 2) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 2) == SIZE_MAX-1); + assert_se(ALIGN_DOWN(SIZE_MAX, 2) == SIZE_MAX-1); + + assert_se(ALIGN_DOWN(0, 4) == 0); + assert_se(ALIGN_DOWN(1, 4) == 0); + assert_se(ALIGN_DOWN(2, 4) == 0); + assert_se(ALIGN_DOWN(3, 4) == 0); + assert_se(ALIGN_DOWN(4, 4) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 4) == SIZE_MAX-3); + assert_se(ALIGN_DOWN(SIZE_MAX, 4) == SIZE_MAX-3); + + assert_se(ALIGN_DOWN_U64(0, 1) == 0); + assert_se(ALIGN_DOWN_U64(1, 1) == 1); + assert_se(ALIGN_DOWN_U64(2, 1) == 2); + assert_se(ALIGN_DOWN_U64(3, 1) == 3); + assert_se(ALIGN_DOWN_U64(4, 1) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 1) == UINT64_MAX-1); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 1) == UINT64_MAX); + + assert_se(ALIGN_DOWN_U64(0, 2) == 0); + assert_se(ALIGN_DOWN_U64(1, 2) == 0); + assert_se(ALIGN_DOWN_U64(2, 2) == 2); + assert_se(ALIGN_DOWN_U64(3, 2) == 2); + assert_se(ALIGN_DOWN_U64(4, 2) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 2) == UINT64_MAX-1); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 2) == UINT64_MAX-1); + + assert_se(ALIGN_DOWN_U64(0, 4) == 0); + assert_se(ALIGN_DOWN_U64(1, 4) == 0); + assert_se(ALIGN_DOWN_U64(2, 4) == 0); + assert_se(ALIGN_DOWN_U64(3, 4) == 0); + assert_se(ALIGN_DOWN_U64(4, 4) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 4) == UINT64_MAX-3); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 4) == UINT64_MAX-3); +} + +TEST(align_offset) { + assert_se(ALIGN_OFFSET(0, 1) == 0); + assert_se(ALIGN_OFFSET(1, 1) == 0); + assert_se(ALIGN_OFFSET(2, 1) == 0); + assert_se(ALIGN_OFFSET(3, 1) == 0); + assert_se(ALIGN_OFFSET(4, 1) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 1) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX, 1) == 0); + + assert_se(ALIGN_OFFSET(0, 2) == 0); + assert_se(ALIGN_OFFSET(1, 2) == 1); + assert_se(ALIGN_OFFSET(2, 2) == 0); + assert_se(ALIGN_OFFSET(3, 2) == 1); + assert_se(ALIGN_OFFSET(4, 2) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 2) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX, 2) == 1); + + assert_se(ALIGN_OFFSET(0, 4) == 0); + assert_se(ALIGN_OFFSET(1, 4) == 1); + assert_se(ALIGN_OFFSET(2, 4) == 2); + assert_se(ALIGN_OFFSET(3, 4) == 3); + assert_se(ALIGN_OFFSET(4, 4) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 4) == 2); + assert_se(ALIGN_OFFSET(SIZE_MAX, 4) == 3); + + assert_se(ALIGN_OFFSET_U64(0, 1) == 0); + assert_se(ALIGN_OFFSET_U64(1, 1) == 0); + assert_se(ALIGN_OFFSET_U64(2, 1) == 0); + assert_se(ALIGN_OFFSET_U64(3, 1) == 0); + assert_se(ALIGN_OFFSET_U64(4, 1) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 1) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 1) == 0); + + assert_se(ALIGN_OFFSET_U64(0, 2) == 0); + assert_se(ALIGN_OFFSET_U64(1, 2) == 1); + assert_se(ALIGN_OFFSET_U64(2, 2) == 0); + assert_se(ALIGN_OFFSET_U64(3, 2) == 1); + assert_se(ALIGN_OFFSET_U64(4, 2) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 2) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 2) == 1); + + assert_se(ALIGN_OFFSET_U64(0, 4) == 0); + assert_se(ALIGN_OFFSET_U64(1, 4) == 1); + assert_se(ALIGN_OFFSET_U64(2, 4) == 2); + assert_se(ALIGN_OFFSET_U64(3, 4) == 3); + assert_se(ALIGN_OFFSET_U64(4, 4) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 4) == 2); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 4) == 3); +} + TEST(flags) { enum { F1 = 1 << 0, diff --git a/src/test/test-memory-util.c b/src/test/test-memory-util.c index 2f8384ac09..cd4b64ac16 100644 --- a/src/test/test-memory-util.c +++ b/src/test/test-memory-util.c @@ -52,4 +52,74 @@ TEST(cleanup_array) { free(saved_iov); } +TEST(page_align) { + assert_se(PAGE_ALIGN(page_size() - 1) == page_size()); + assert_se(PAGE_ALIGN(page_size() ) == page_size()); + assert_se(PAGE_ALIGN(page_size() + 1) == page_size() * 2); + assert_se(PAGE_ALIGN(page_size() * 123 - 1) == page_size() * 123); + assert_se(PAGE_ALIGN(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN(page_size() * 123 + 1) == page_size() * 124); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() + 2) == SIZE_MAX); /* overflow */ + assert_se(PAGE_ALIGN(SIZE_MAX) == SIZE_MAX); /* overflow */ + + assert_se(PAGE_ALIGN_U64(page_size() - 1) == page_size()); + assert_se(PAGE_ALIGN_U64(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_U64(page_size() + 1) == page_size() * 2); + assert_se(PAGE_ALIGN_U64(page_size() * 123 - 1) == page_size() * 123); + assert_se(PAGE_ALIGN_U64(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_U64(page_size() * 123 + 1) == page_size() * 124); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() - 1) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() ) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() + 1) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() + 2) == UINT64_MAX); /* overflow */ + assert_se(PAGE_ALIGN_U64(UINT64_MAX) == UINT64_MAX); /* overflow */ + + assert_se(PAGE_ALIGN_DOWN(page_size() - 1) == 0); + assert_se(PAGE_ALIGN_DOWN(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_DOWN(page_size() + 1) == page_size()); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 - 1) == page_size() * 122); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 + 1) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() + 2) == SIZE_MAX - page_size() + 1); + + assert_se(PAGE_ALIGN_DOWN_U64(page_size() - 1) == 0); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() + 1) == page_size()); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 - 1) == page_size() * 122); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 + 1) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() + 2) == SIZE_MAX - page_size() + 1); + + assert_se(PAGE_OFFSET(page_size() - 1) == page_size() - 1); + assert_se(PAGE_OFFSET(page_size() ) == 0); + assert_se(PAGE_OFFSET(page_size() + 1) == 1); + assert_se(PAGE_OFFSET(page_size() * 123 - 1) == page_size() - 1); + assert_se(PAGE_OFFSET(page_size() * 123 ) == 0); + assert_se(PAGE_OFFSET(page_size() * 123 + 1) == 1); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() - 1) == page_size() - 2); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() ) == page_size() - 1); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() + 1) == 0); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() + 2) == 1); + + assert_se(PAGE_OFFSET_U64(page_size() - 1) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(page_size() ) == 0); + assert_se(PAGE_OFFSET_U64(page_size() + 1) == 1); + assert_se(PAGE_OFFSET_U64(page_size() * 123 - 1) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(page_size() * 123 ) == 0); + assert_se(PAGE_OFFSET_U64(page_size() * 123 + 1) == 1); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() - 1) == page_size() - 2); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() ) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() + 1) == 0); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() + 2) == 1); +} + DEFINE_TEST_MAIN(LOG_INFO); |