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.
This commit is contained in:
iceman1001
2026-09-03 16:55:15 +02:00
parent 08a31f01db
commit 54bbff4c8c
+15 -12
View File
@@ -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, &sector_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);