]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
macro: handle overflow in ALIGN_TO() somewhat reasonably 20499/head
authorLennart Poettering <lennart@poettering.net>
Fri, 20 Aug 2021 16:11:14 +0000 (18:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 20 Aug 2021 20:00:48 +0000 (22:00 +0200)
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
src/test/test-macro.c

index 280f3028643ecdded3768cc229eceb03c54caaeb..6977a1ddd94b47be46c85772a922574bbedc1291 100644 (file)
 #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));
 }
 
index 5c0007cb5be6ccd0727c6632d88b958a6303b52b..428f3b952ae54fbfdb21cb4312e4cc02afc683ba 100644 (file)
@@ -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;
 }