From eeed637fea380c59e90e707c684e8db32714baa4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2021 18:28:21 +0200 Subject: [PATCH 1/2] test: split out macro tests into own test-macro.c No changes in code, just a split out of tests for stuff from macro.h into test-macro.c --- src/test/meson.build | 2 + src/test/test-macro.c | 310 ++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 296 ---------------------------------------- 3 files changed, 312 insertions(+), 296 deletions(-) create mode 100644 src/test/test-macro.c diff --git a/src/test/meson.build b/src/test/meson.build index ad226418e2..46b497672f 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -188,6 +188,8 @@ tests += [ [['src/test/test-util.c']], + [['src/test/test-macro.c']], + [['src/test/test-json.c']], [['src/test/test-modhex.c']], diff --git a/src/test/test-macro.c b/src/test/test-macro.c new file mode 100644 index 0000000000..5c0007cb5b --- /dev/null +++ b/src/test/test-macro.c @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "log.h" +#include "macro.h" +#include "tests.h" + +static void test_align_power2(void) { + unsigned long i, p2; + + log_info("/* %s */", __func__); + + assert_se(ALIGN_POWER2(0) == 0); + assert_se(ALIGN_POWER2(1) == 1); + assert_se(ALIGN_POWER2(2) == 2); + assert_se(ALIGN_POWER2(3) == 4); + assert_se(ALIGN_POWER2(4) == 4); + assert_se(ALIGN_POWER2(5) == 8); + assert_se(ALIGN_POWER2(6) == 8); + assert_se(ALIGN_POWER2(7) == 8); + assert_se(ALIGN_POWER2(9) == 16); + assert_se(ALIGN_POWER2(10) == 16); + assert_se(ALIGN_POWER2(11) == 16); + assert_se(ALIGN_POWER2(12) == 16); + assert_se(ALIGN_POWER2(13) == 16); + assert_se(ALIGN_POWER2(14) == 16); + assert_se(ALIGN_POWER2(15) == 16); + assert_se(ALIGN_POWER2(16) == 16); + assert_se(ALIGN_POWER2(17) == 32); + + assert_se(ALIGN_POWER2(ULONG_MAX) == 0); + assert_se(ALIGN_POWER2(ULONG_MAX - 1) == 0); + assert_se(ALIGN_POWER2(ULONG_MAX - 1024) == 0); + assert_se(ALIGN_POWER2(ULONG_MAX / 2) == ULONG_MAX / 2 + 1); + assert_se(ALIGN_POWER2(ULONG_MAX + 1) == 0); + + for (i = 1; i < 131071; ++i) { + for (p2 = 1; p2 < i; p2 <<= 1) + /* empty */ ; + + assert_se(ALIGN_POWER2(i) == p2); + } + + for (i = ULONG_MAX - 1024; i < ULONG_MAX; ++i) { + for (p2 = 1; p2 && p2 < i; p2 <<= 1) + /* empty */ ; + + assert_se(ALIGN_POWER2(i) == p2); + } +} + +static void test_max(void) { + static const struct { + int a; + int b[CONST_MAX(10, 100)]; + } val1 = { + .a = CONST_MAX(10, 100), + }; + int d = 0; + unsigned long x = 12345; + unsigned long y = 54321; + const char str[] = "a_string_constant"; + const unsigned long long arr[] = {9999ULL, 10ULL, 0ULL, 3000ULL, 2000ULL, 1000ULL, 100ULL, 9999999ULL}; + void *p = (void *)str; + void *q = (void *)&str[16]; + + log_info("/* %s */", __func__); + + assert_cc(sizeof(val1.b) == sizeof(int) * 100); + + /* CONST_MAX returns (void) instead of a value if the passed arguments + * are not of the same type or not constant expressions. */ + assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 10)), int)); + assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 1U)), void)); + + assert_se(val1.a == 100); + assert_se(MAX(++d, 0) == 1); + assert_se(d == 1); + + assert_cc(MAXSIZE(char[3], uint16_t) == 3); + assert_cc(MAXSIZE(char[3], uint32_t) == 4); + assert_cc(MAXSIZE(char, long) == sizeof(long)); + + assert_se(MAX(-5, 5) == 5); + assert_se(MAX(5, 5) == 5); + assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5); + assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3); + assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5); + assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2); + assert_se(LESS_BY(8, 4) == 4); + assert_se(LESS_BY(8, 8) == 0); + assert_se(LESS_BY(4, 8) == 0); + assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); + assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); + assert_se(CMP(3, 5) == -1); + assert_se(CMP(5, 3) == 1); + assert_se(CMP(5, 5) == 0); + assert_se(CMP(x, y) == -1); + assert_se(CMP(y, x) == 1); + assert_se(CMP(x, x) == 0); + assert_se(CMP(y, y) == 0); + assert_se(CMP(UINT64_MAX, (uint64_t) 0) == 1); + assert_se(CMP((uint64_t) 0, UINT64_MAX) == -1); + assert_se(CMP(UINT64_MAX, UINT64_MAX) == 0); + assert_se(CMP(INT64_MIN, INT64_MAX) == -1); + assert_se(CMP(INT64_MAX, INT64_MIN) == 1); + assert_se(CMP(INT64_MAX, INT64_MAX) == 0); + assert_se(CMP(INT64_MIN, INT64_MIN) == 0); + assert_se(CMP(INT64_MAX, (int64_t) 0) == 1); + assert_se(CMP((int64_t) 0, INT64_MIN) == 1); + assert_se(CMP(INT64_MIN, (int64_t) 0) == -1); + assert_se(CMP((int64_t) 0, INT64_MAX) == -1); + assert_se(CMP(&str[2], &str[7]) == -1); + assert_se(CMP(&str[2], &str[2]) == 0); + assert_se(CMP(&str[7], (const char *)str) == 1); + assert_se(CMP(str[2], str[7]) == 1); + assert_se(CMP(str[7], *str) == 1); + assert_se(CMP((const unsigned long long *)arr, &arr[3]) == -1); + assert_se(CMP(*arr, arr[3]) == 1); + assert_se(CMP(p, q) == -1); + assert_se(CMP(q, p) == 1); + assert_se(CMP(p, p) == 0); + assert_se(CMP(q, q) == 0); + assert_se(CLAMP(-5, 0, 1) == 0); + assert_se(CLAMP(5, 0, 1) == 1); + assert_se(CLAMP(5, -10, 1) == 1); + assert_se(CLAMP(5, -10, 10) == 5); + assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10); +} + +#pragma GCC diagnostic push +#ifdef __clang__ +# pragma GCC diagnostic ignored "-Waddress-of-packed-member" +#endif + +static void test_container_of(void) { + struct mytype { + uint8_t pad1[3]; + uint64_t v1; + uint8_t pad2[2]; + uint32_t v2; + } myval = { }; + + log_info("/* %s */", __func__); + + assert_cc(sizeof(myval) >= 17); + assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); + assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); + assert_se(container_of(&container_of(&myval.v2, + struct mytype, + v2)->v1, + struct mytype, + v1) == &myval); +} + +#pragma GCC diagnostic pop + +static void test_div_round_up(void) { + int div; + + log_info("/* %s */", __func__); + + /* basic tests */ + assert_se(DIV_ROUND_UP(0, 8) == 0); + assert_se(DIV_ROUND_UP(1, 8) == 1); + assert_se(DIV_ROUND_UP(8, 8) == 1); + assert_se(DIV_ROUND_UP(12, 8) == 2); + assert_se(DIV_ROUND_UP(16, 8) == 2); + + /* test multiple evaluation */ + div = 0; + assert_se(DIV_ROUND_UP(div++, 8) == 0 && div == 1); + assert_se(DIV_ROUND_UP(++div, 8) == 1 && div == 2); + assert_se(DIV_ROUND_UP(8, div++) == 4 && div == 3); + assert_se(DIV_ROUND_UP(8, ++div) == 2 && div == 4); + + /* overflow test with exact division */ + assert_se(sizeof(0U) == 4); + assert_se(0xfffffffaU % 10U == 0U); + assert_se(0xfffffffaU / 10U == 429496729U); + assert_se(DIV_ROUND_UP(0xfffffffaU, 10U) == 429496729U); + assert_se((0xfffffffaU + 10U - 1U) / 10U == 0U); + assert_se(0xfffffffaU / 10U + !!(0xfffffffaU % 10U) == 429496729U); + + /* overflow test with rounded division */ + assert_se(0xfffffffdU % 10U == 3U); + assert_se(0xfffffffdU / 10U == 429496729U); + assert_se(DIV_ROUND_UP(0xfffffffdU, 10U) == 429496730U); + assert_se((0xfffffffdU + 10U - 1U) / 10U == 0U); + assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); +} + +static void test_ptr_to_int(void) { + log_info("/* %s */", __func__); + + /* Primary reason to have this test is to validate that pointers are large enough to hold entire int range */ + assert_se(PTR_TO_INT(INT_TO_PTR(0)) == 0); + assert_se(PTR_TO_INT(INT_TO_PTR(1)) == 1); + assert_se(PTR_TO_INT(INT_TO_PTR(-1)) == -1); + assert_se(PTR_TO_INT(INT_TO_PTR(INT_MAX)) == INT_MAX); + assert_se(PTR_TO_INT(INT_TO_PTR(INT_MIN)) == INT_MIN); +} + +static void test_in_set(void) { + log_info("/* %s */", __func__); + + assert_se(IN_SET(1, 1)); + assert_se(IN_SET(1, 1, 2, 3, 4)); + assert_se(IN_SET(2, 1, 2, 3, 4)); + assert_se(IN_SET(3, 1, 2, 3, 4)); + assert_se(IN_SET(4, 1, 2, 3, 4)); + assert_se(!IN_SET(0, 1)); + assert_se(!IN_SET(0, 1, 2, 3, 4)); +} + +static void test_foreach_pointer(void) { + int a, b, c, *i; + size_t k = 0; + + log_info("/* %s */", __func__); + + FOREACH_POINTER(i, &a, &b, &c) { + switch (k) { + + case 0: + assert_se(i == &a); + break; + + case 1: + assert_se(i == &b); + break; + + case 2: + assert_se(i == &c); + break; + + default: + assert_not_reached(); + break; + } + + k++; + } + + assert(k == 3); + + FOREACH_POINTER(i, &b) { + assert(k == 3); + assert(i == &b); + k = 4; + } + + assert(k == 4); + + FOREACH_POINTER(i, NULL, &c, NULL, &b, NULL, &a, NULL) { + switch (k) { + + case 4: + assert_se(i == NULL); + break; + + case 5: + assert_se(i == &c); + break; + + case 6: + assert_se(i == NULL); + break; + + case 7: + assert_se(i == &b); + break; + + case 8: + assert_se(i == NULL); + break; + + case 9: + assert_se(i == &a); + break; + + case 10: + assert_se(i == NULL); + break; + + default: + assert_not_reached(); + break; + } + + k++; + } + + assert(k == 11); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + test_align_power2(); + test_max(); + test_container_of(); + test_div_round_up(); + test_in_set(); + test_foreach_pointer(); + test_ptr_to_int(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 4d9008ba33..8a9ac9058a 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -17,191 +17,6 @@ #include "tests.h" #include "util.h" -static void test_align_power2(void) { - unsigned long i, p2; - - log_info("/* %s */", __func__); - - assert_se(ALIGN_POWER2(0) == 0); - assert_se(ALIGN_POWER2(1) == 1); - assert_se(ALIGN_POWER2(2) == 2); - assert_se(ALIGN_POWER2(3) == 4); - assert_se(ALIGN_POWER2(4) == 4); - assert_se(ALIGN_POWER2(5) == 8); - assert_se(ALIGN_POWER2(6) == 8); - assert_se(ALIGN_POWER2(7) == 8); - assert_se(ALIGN_POWER2(9) == 16); - assert_se(ALIGN_POWER2(10) == 16); - assert_se(ALIGN_POWER2(11) == 16); - assert_se(ALIGN_POWER2(12) == 16); - assert_se(ALIGN_POWER2(13) == 16); - assert_se(ALIGN_POWER2(14) == 16); - assert_se(ALIGN_POWER2(15) == 16); - assert_se(ALIGN_POWER2(16) == 16); - assert_se(ALIGN_POWER2(17) == 32); - - assert_se(ALIGN_POWER2(ULONG_MAX) == 0); - assert_se(ALIGN_POWER2(ULONG_MAX - 1) == 0); - assert_se(ALIGN_POWER2(ULONG_MAX - 1024) == 0); - assert_se(ALIGN_POWER2(ULONG_MAX / 2) == ULONG_MAX / 2 + 1); - assert_se(ALIGN_POWER2(ULONG_MAX + 1) == 0); - - for (i = 1; i < 131071; ++i) { - for (p2 = 1; p2 < i; p2 <<= 1) - /* empty */ ; - - assert_se(ALIGN_POWER2(i) == p2); - } - - for (i = ULONG_MAX - 1024; i < ULONG_MAX; ++i) { - for (p2 = 1; p2 && p2 < i; p2 <<= 1) - /* empty */ ; - - assert_se(ALIGN_POWER2(i) == p2); - } -} - -static void test_max(void) { - static const struct { - int a; - int b[CONST_MAX(10, 100)]; - } val1 = { - .a = CONST_MAX(10, 100), - }; - int d = 0; - unsigned long x = 12345; - unsigned long y = 54321; - const char str[] = "a_string_constant"; - const unsigned long long arr[] = {9999ULL, 10ULL, 0ULL, 3000ULL, 2000ULL, 1000ULL, 100ULL, 9999999ULL}; - void *p = (void *)str; - void *q = (void *)&str[16]; - - log_info("/* %s */", __func__); - - assert_cc(sizeof(val1.b) == sizeof(int) * 100); - - /* CONST_MAX returns (void) instead of a value if the passed arguments - * are not of the same type or not constant expressions. */ - assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 10)), int)); - assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 1U)), void)); - - assert_se(val1.a == 100); - assert_se(MAX(++d, 0) == 1); - assert_se(d == 1); - - assert_cc(MAXSIZE(char[3], uint16_t) == 3); - assert_cc(MAXSIZE(char[3], uint32_t) == 4); - assert_cc(MAXSIZE(char, long) == sizeof(long)); - - assert_se(MAX(-5, 5) == 5); - assert_se(MAX(5, 5) == 5); - assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5); - assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3); - assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5); - assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2); - assert_se(LESS_BY(8, 4) == 4); - assert_se(LESS_BY(8, 8) == 0); - assert_se(LESS_BY(4, 8) == 0); - assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); - assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); - assert_se(CMP(3, 5) == -1); - assert_se(CMP(5, 3) == 1); - assert_se(CMP(5, 5) == 0); - assert_se(CMP(x, y) == -1); - assert_se(CMP(y, x) == 1); - assert_se(CMP(x, x) == 0); - assert_se(CMP(y, y) == 0); - assert_se(CMP(UINT64_MAX, (uint64_t) 0) == 1); - assert_se(CMP((uint64_t) 0, UINT64_MAX) == -1); - assert_se(CMP(UINT64_MAX, UINT64_MAX) == 0); - assert_se(CMP(INT64_MIN, INT64_MAX) == -1); - assert_se(CMP(INT64_MAX, INT64_MIN) == 1); - assert_se(CMP(INT64_MAX, INT64_MAX) == 0); - assert_se(CMP(INT64_MIN, INT64_MIN) == 0); - assert_se(CMP(INT64_MAX, (int64_t) 0) == 1); - assert_se(CMP((int64_t) 0, INT64_MIN) == 1); - assert_se(CMP(INT64_MIN, (int64_t) 0) == -1); - assert_se(CMP((int64_t) 0, INT64_MAX) == -1); - assert_se(CMP(&str[2], &str[7]) == -1); - assert_se(CMP(&str[2], &str[2]) == 0); - assert_se(CMP(&str[7], (const char *)str) == 1); - assert_se(CMP(str[2], str[7]) == 1); - assert_se(CMP(str[7], *str) == 1); - assert_se(CMP((const unsigned long long *)arr, &arr[3]) == -1); - assert_se(CMP(*arr, arr[3]) == 1); - assert_se(CMP(p, q) == -1); - assert_se(CMP(q, p) == 1); - assert_se(CMP(p, p) == 0); - assert_se(CMP(q, q) == 0); - assert_se(CLAMP(-5, 0, 1) == 0); - assert_se(CLAMP(5, 0, 1) == 1); - assert_se(CLAMP(5, -10, 1) == 1); - assert_se(CLAMP(5, -10, 10) == 5); - assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10); -} - -#pragma GCC diagnostic push -#ifdef __clang__ -# pragma GCC diagnostic ignored "-Waddress-of-packed-member" -#endif - -static void test_container_of(void) { - struct mytype { - uint8_t pad1[3]; - uint64_t v1; - uint8_t pad2[2]; - uint32_t v2; - } myval = { }; - - log_info("/* %s */", __func__); - - assert_cc(sizeof(myval) >= 17); - assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); - assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); - assert_se(container_of(&container_of(&myval.v2, - struct mytype, - v2)->v1, - struct mytype, - v1) == &myval); -} - -#pragma GCC diagnostic pop - -static void test_div_round_up(void) { - int div; - - log_info("/* %s */", __func__); - - /* basic tests */ - assert_se(DIV_ROUND_UP(0, 8) == 0); - assert_se(DIV_ROUND_UP(1, 8) == 1); - assert_se(DIV_ROUND_UP(8, 8) == 1); - assert_se(DIV_ROUND_UP(12, 8) == 2); - assert_se(DIV_ROUND_UP(16, 8) == 2); - - /* test multiple evaluation */ - div = 0; - assert_se(DIV_ROUND_UP(div++, 8) == 0 && div == 1); - assert_se(DIV_ROUND_UP(++div, 8) == 1 && div == 2); - assert_se(DIV_ROUND_UP(8, div++) == 4 && div == 3); - assert_se(DIV_ROUND_UP(8, ++div) == 2 && div == 4); - - /* overflow test with exact division */ - assert_se(sizeof(0U) == 4); - assert_se(0xfffffffaU % 10U == 0U); - assert_se(0xfffffffaU / 10U == 429496729U); - assert_se(DIV_ROUND_UP(0xfffffffaU, 10U) == 429496729U); - assert_se((0xfffffffaU + 10U - 1U) / 10U == 0U); - assert_se(0xfffffffaU / 10U + !!(0xfffffffaU % 10U) == 429496729U); - - /* overflow test with rounded division */ - assert_se(0xfffffffdU % 10U == 3U); - assert_se(0xfffffffdU / 10U == 429496729U); - assert_se(DIV_ROUND_UP(0xfffffffdU, 10U) == 429496730U); - assert_se((0xfffffffdU + 10U - 1U) / 10U == 0U); - assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); -} - static void test_u64log2(void) { log_info("/* %s */", __func__); @@ -249,18 +64,6 @@ static void test_unprotect_errno(void) { assert_se(errno == 4711); } -static void test_in_set(void) { - log_info("/* %s */", __func__); - - assert_se(IN_SET(1, 1)); - assert_se(IN_SET(1, 1, 2, 3, 4)); - assert_se(IN_SET(2, 1, 2, 3, 4)); - assert_se(IN_SET(3, 1, 2, 3, 4)); - assert_se(IN_SET(4, 1, 2, 3, 4)); - assert_se(!IN_SET(0, 1)); - assert_se(!IN_SET(0, 1, 2, 3, 4)); -} - static void test_log2i(void) { log_info("/* %s */", __func__); @@ -409,109 +212,12 @@ static void test_system_tasks_max_scale(void) { assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } -static void test_foreach_pointer(void) { - int a, b, c, *i; - size_t k = 0; - - log_info("/* %s */", __func__); - - FOREACH_POINTER(i, &a, &b, &c) { - switch (k) { - - case 0: - assert_se(i == &a); - break; - - case 1: - assert_se(i == &b); - break; - - case 2: - assert_se(i == &c); - break; - - default: - assert_not_reached(); - break; - } - - k++; - } - - assert(k == 3); - - FOREACH_POINTER(i, &b) { - assert(k == 3); - assert(i == &b); - k = 4; - } - - assert(k == 4); - - FOREACH_POINTER(i, NULL, &c, NULL, &b, NULL, &a, NULL) { - switch (k) { - - case 4: - assert_se(i == NULL); - break; - - case 5: - assert_se(i == &c); - break; - - case 6: - assert_se(i == NULL); - break; - - case 7: - assert_se(i == &b); - break; - - case 8: - assert_se(i == NULL); - break; - - case 9: - assert_se(i == &a); - break; - - case 10: - assert_se(i == NULL); - break; - - default: - assert_not_reached(); - break; - } - - k++; - } - - assert(k == 11); -} - -static void test_ptr_to_int(void) { - log_info("/* %s */", __func__); - - /* Primary reason to have this test is to validate that pointers are large enough to hold entire int range */ - assert_se(PTR_TO_INT(INT_TO_PTR(0)) == 0); - assert_se(PTR_TO_INT(INT_TO_PTR(1)) == 1); - assert_se(PTR_TO_INT(INT_TO_PTR(-1)) == -1); - assert_se(PTR_TO_INT(INT_TO_PTR(INT_MAX)) == INT_MAX); - assert_se(PTR_TO_INT(INT_TO_PTR(INT_MIN)) == INT_MIN); -} - int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); - test_align_power2(); - test_max(); - test_container_of(); - test_div_round_up(); test_u64log2(); test_protect_errno(); test_unprotect_errno(); - test_in_set(); test_log2i(); test_eqzero(); test_raw_clone(); @@ -519,8 +225,6 @@ int main(int argc, char *argv[]) { test_physical_memory_scale(); test_system_tasks_max(); test_system_tasks_max_scale(); - test_foreach_pointer(); - test_ptr_to_int(); return 0; } From c7ed7187203ca0b348a0bb8a355b01332c446101 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2021 18:11:14 +0200 Subject: [PATCH 2/2] macro: handle overflow in ALIGN_TO() somewhat reasonably The helper call rounds up to next multiple of specified boundary. If one passes a very large value as first argument, then there might not be a next multiple. So far we ignored that. Let's handle this now and return SIZE_MAX in this case, as special indicator that we reached the end. Of course, IRL this should not happen. With this new change we at least do something somewhat reasonable, leaving it to the caller to handle it further. --- src/basic/macro.h | 14 ++++++++++++++ src/test/test-macro.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/basic/macro.h b/src/basic/macro.h index 280f302864..6977a1ddd9 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -146,6 +146,20 @@ #define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) static inline size_t ALIGN_TO(size_t l, size_t ali) { + /* Check that alignment is exponent of 2 */ +#if SIZE_MAX == UINT_MAX + assert(__builtin_popcount(ali) == 1); +#elif SIZE_MAX == ULONG_MAX + assert(__builtin_popcountl(ali) == 1); +#elif SIZE_MAX == ULONGLONG_MAX + assert(__builtin_popcountll(ali) == 1); +#else +#error "Unexpected size_t" +#endif + + if (l > SIZE_MAX - (ali - 1)) + return SIZE_MAX; /* indicate overflow */ + return ((l + ali - 1) & ~(ali - 1)); } diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 5c0007cb5b..428f3b952a 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -295,6 +295,38 @@ static void test_foreach_pointer(void) { assert(k == 11); } +static void test_align_to(void) { + log_info("/* %s */", __func__); + + assert_se(ALIGN_TO(0, 1) == 0); + assert_se(ALIGN_TO(1, 1) == 1); + assert_se(ALIGN_TO(2, 1) == 2); + assert_se(ALIGN_TO(3, 1) == 3); + assert_se(ALIGN_TO(4, 1) == 4); + assert_se(ALIGN_TO(SIZE_MAX-1, 1) == SIZE_MAX-1); + assert_se(ALIGN_TO(SIZE_MAX, 1) == SIZE_MAX); + + assert_se(ALIGN_TO(0, 2) == 0); + assert_se(ALIGN_TO(1, 2) == 2); + assert_se(ALIGN_TO(2, 2) == 2); + assert_se(ALIGN_TO(3, 2) == 4); + assert_se(ALIGN_TO(4, 2) == 4); + assert_se(ALIGN_TO(SIZE_MAX-3, 2) == SIZE_MAX-3); + assert_se(ALIGN_TO(SIZE_MAX-2, 2) == SIZE_MAX-1); + assert_se(ALIGN_TO(SIZE_MAX-1, 2) == SIZE_MAX-1); + assert_se(ALIGN_TO(SIZE_MAX, 2) == SIZE_MAX); /* overflow */ + + assert_se(ALIGN_TO(0, 4) == 0); + assert_se(ALIGN_TO(1, 4) == 4); + assert_se(ALIGN_TO(2, 4) == 4); + assert_se(ALIGN_TO(3, 4) == 4); + assert_se(ALIGN_TO(4, 4) == 4); + assert_se(ALIGN_TO(SIZE_MAX-3, 4) == SIZE_MAX-3); + assert_se(ALIGN_TO(SIZE_MAX-2, 4) == SIZE_MAX); /* overflow */ + assert_se(ALIGN_TO(SIZE_MAX-1, 4) == SIZE_MAX); /* overflow */ + assert_se(ALIGN_TO(SIZE_MAX, 4) == SIZE_MAX); /* overflow */ +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); @@ -305,6 +337,7 @@ int main(int argc, char *argv[]) { test_in_set(); test_foreach_pointer(); test_ptr_to_int(); + test_align_to(); return 0; }