From 50996f04ad1b2db36bb210c1bd1c3526f861ea45 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 21 Mar 2022 14:23:38 +0100 Subject: [PATCH] macro: add macro that simplifies going backwards through an array via pointers Inspired by #22797, let's avoid some UB when iterating through arrays. --- src/basic/macro.h | 16 ++++++++++++++++ src/test/test-macro.c | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/basic/macro.h b/src/basic/macro.h index fb1ae65d28..68d8b062e8 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -463,4 +463,20 @@ typedef struct { assert_cc(sizeof(dummy_t) == 0); +/* A little helper for subtracting 1 off a pointer in a safe UB-free way. This is intended to be used for for + * loops that count down from a high pointer until some base. A naive loop would implement this like this: + * + * for (p = end-1; p >= base; p--) … + * + * But this is not safe because p before the base is UB in C. With this macro the loop becomes this instead: + * + * for (p = PTR_SUB1(end, base); p; p = PTR_SUB1(p, base)) … + * + * And is free from UB! */ +#define PTR_SUB1(p, base) \ + ({ \ + typeof(p) _q = (p); \ + _q && _q > (base) ? &_q[-1] : NULL; \ + }) + #include "log.h" diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 960ff4bc09..ba319953cd 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -433,4 +433,27 @@ TEST(DECIMAL_STR_MAX) { assert_se(DECIMAL_STR_MAX(uint64_t) == DECIMAL_STR_WIDTH(u64_longest)+1); } +TEST(PTR_SUB1) { + static const uint64_t x[4] = { 2, 3, 4, 5 }; + const uint64_t *p; + + p = x + ELEMENTSOF(x)-1; + assert_se(*p == 5); + + p = PTR_SUB1(p, x); + assert_se(*p == 4); + + p = PTR_SUB1(p, x); + assert_se(*p == 3); + + p = PTR_SUB1(p, x); + assert_se(*p == 2); + + p = PTR_SUB1(p, x); + assert_se(!p); + + p = PTR_SUB1(p, x); + assert_se(!p); +} + DEFINE_TEST_MAIN(LOG_INFO); -- 2.25.1