From 8c039cc72d88735f055b6102b63d031cd835e28d Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 10 Sep 2026 18:36:50 +0200 Subject: [PATCH] Replace mem_is_zero() with membcmp() and update call sites --- cmdline/check.c | 4 ++-- cmdline/selftest.c | 23 ++++++++++++++++++++--- cmdline/util.h | 39 +++++++++++++++------------------------ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/cmdline/check.c b/cmdline/check.c index 6ad02b9c..a74b3dc4 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -342,7 +342,7 @@ static int block_data_cmp(struct snapraid_state* state, int rehash, struct snapr * but also makes the canonical-block invariant explicit. */ if (pos_size < state->block_size) { - if (!mem_is_zero(buffer + pos_size, state->block_size - pos_size)) { + if (membcmp(buffer + pos_size, 0, state->block_size - pos_size) != 0) { return -1; } } @@ -1036,7 +1036,7 @@ static int repair(struct snapraid_state* state, int rehash, block_off_t pos, uns * A zero candidate is ambiguous because OLD and CURRENT * may legitimately contain the same zero block. */ - if (!mem_is_zero(buffer[failed[j].index], state->block_size)) + if (membcmp(buffer[failed[j].index], 0, state->block_size) != 0) current_generation_proven = 1; } else { unsigned hash_kind; diff --git a/cmdline/selftest.c b/cmdline/selftest.c index 61db7912..4ec85cbe 100644 --- a/cmdline/selftest.c +++ b/cmdline/selftest.c @@ -2151,19 +2151,36 @@ static void test_misc(int argc, char* argv[]) unsigned zi, zj; memset(zbuf, 0, sizeof(zbuf)); - assert(mem_is_zero(zbuf, 0) != 0); + assert(membcmp(zbuf, 0, 0) == 0); for (zi = 0; zi < sizeof(zbuf); ++zi) { for (zj = zi; zj <= sizeof(zbuf); ++zj) { - assert(mem_is_zero(zbuf + zi, zj - zi) != 0); + assert(membcmp(zbuf + zi, 0, zj - zi) == 0); } } for (zi = 0; zi < sizeof(zbuf); ++zi) { zbuf[zi] = 1; - assert(mem_is_zero(zbuf, sizeof(zbuf)) == 0); + assert(membcmp(zbuf, 0, sizeof(zbuf)) > 0); zbuf[zi] = 0; } + + memset(zbuf, 1, sizeof(zbuf)); + assert(membcmp(zbuf, 1, 0) == 0); + + for (zi = 0; zi < sizeof(zbuf); ++zi) { + for (zj = zi; zj <= sizeof(zbuf); ++zj) { + assert(membcmp(zbuf + zi, 1, zj - zi) == 0); + } + } + + for (zi = 0; zi < sizeof(zbuf); ++zi) { + zbuf[zi] = 0; + assert(membcmp(zbuf, 1, sizeof(zbuf)) < 0); + zbuf[zi] = 2; + assert(membcmp(zbuf, 1, sizeof(zbuf)) > 0); + zbuf[zi] = 1; + } } for (i = 2; i < argc; ++i) { diff --git a/cmdline/util.h b/cmdline/util.h index 4338022a..eb9053f3 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -39,34 +39,25 @@ void** malloc_nofail_vector_direct(int n, size_t size, void** freeptr); void mtest_vector(int n, size_t size, void** vv); /** - * Return !=0 if the memory region is completely filled with zeros. + * Compare memory against a repeated byte value. + * + * Return <0 if ptr is less than value, 0 if equal, >0 if greater. */ -static inline int mem_is_zero(const void* ptr, size_t size) +static __always_inline int membcmp(const void* ptr, uint8_t value, size_t size) { - const unsigned char* p = ptr; + const uint8_t* p = ptr; - while (size != 0 && ((uintptr_t)p % sizeof(size_t)) != 0) { - if (*p != 0) - return 0; - ++p; - --size; - } + if (size == 0) + return 0; + if (p[0] != value) + return (int)p[0] - (int)value; - while (size >= sizeof(size_t)) { - if (*(const size_t*)p != 0) - return 0; - p += sizeof(size_t); - size -= sizeof(size_t); - } - - while (size != 0) { - if (*p != 0) - return 0; - ++p; - --size; - } - - return 1; + /* + * If the buffer contains value up to index k-1, then at offset k-1 + * memcmp compares (p + 1)[k - 1] = p[k] against p[k - 1] = value. + * The first differing adjacent pair yields the exact sign (p[k] - value). + */ + return memcmp(p + 1, p, size - 1); } /****************************************************************************/