From 54bbff4c8ce0ae56dcae924797bb39199618a948 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 3 Sep 2026 16:55:15 +0200 Subject: [PATCH] hf mad: fix aarch64 -Wstringop-overflow false positive in mad encode GCC on aarch64 vectorizes the sector fill loop in parse_sector_ranges() into 16-byte NEON stores. When it versions the loop it loses the range relationship between count and max_sectors, and reports a 16-byte store into the last 8 bytes of sectors[40]. The code was correct; the guard was there. Does not reproduce on x86-64 gcc 14. Accumulate sectors in a uint64_t bitmask instead of an array, so there is no store for -Wstringop-overflow to mis-size on any target. Sector numbers are already validated to 1..39, so the bound check is no longer needed. Supersedes the sectors[48] padding, which only absorbs a 16-byte vector and would regress on wider ones. Side effect: duplicate sectors within a single --aid argument now dedupe instead of erroring (E103:1-3,2 encodes 1-3). Conflicts between different --aid arguments still error. --- client/src/cmdmad.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/client/src/cmdmad.c b/client/src/cmdmad.c index d7078628a..b20d1fbb0 100644 --- a/client/src/cmdmad.c +++ b/client/src/cmdmad.c @@ -501,9 +501,9 @@ static int CmdMADDecode(const char *Cmd) { // --- Encode --- -// parse "1-3,5,7-9" into sector numbers, returns count or -1 on error -static int parse_sector_ranges(const char *str, uint8_t *sectors, int max_sectors) { - int count = 0; +// parse "1-3,5,7-9" into a bitmask of sector numbers, returns count or -1 on error +static int parse_sector_ranges(const char *str, uint64_t *sector_mask) { + uint64_t mask = 0; const char *p = str; while (*p) { @@ -541,10 +541,7 @@ static int parse_sector_ranges(const char *str, uint8_t *sectors, int max_sector PrintAndLogEx(ERR, "Sector " _YELLOW_("%ld") " is reserved for MAD directory", s); return -1; } - if (count >= max_sectors) { - return -1; - } - sectors[count++] = (uint8_t)s; + mask |= (1ULL << s); } p = end; @@ -553,7 +550,9 @@ static int parse_sector_ranges(const char *str, uint8_t *sectors, int max_sector p++; } } - return count; + + *sector_mask = mask; + return __builtin_popcountll(mask); } static int CmdMADEncode(const char *Cmd) { @@ -601,16 +600,20 @@ static int CmdMADEncode(const char *Cmd) { memcpy(aid_str, val, 4); uint16_t aid_val = (uint16_t)strtoul(aid_str, NULL, 16); - uint8_t sectors[48] = {0}; - int nsectors = parse_sector_ranges(colon + 1, sectors, 40); + uint64_t sector_mask = 0; + int nsectors = parse_sector_ranges(colon + 1, §or_mask); if (nsectors <= 0) { PrintAndLogEx(ERR, "Invalid sector range in " _YELLOW_("'%s'"), val); CLIParserFree(ctx); return PM3_EINVARG; } - for (int s = 0; s < nsectors; s++) { - uint8_t sno = sectors[s]; + for (uint8_t sno = 1; sno < 40; sno++) { + + if ((sector_mask & (1ULL << sno)) == 0) { + continue; + } + if (sector_aids[sno] != 0) { PrintAndLogEx(ERR, "Sector " _YELLOW_("%d") " already assigned to AID " _YELLOW_("0x%04X"), sno, sector_aids[sno]); CLIParserFree(ctx);