diff --git a/include/diagnostics.hpp b/include/diagnostics.hpp index a529d2f7..6274d93f 100644 --- a/include/diagnostics.hpp +++ b/include/diagnostics.hpp @@ -28,7 +28,7 @@ struct WarningState { void update(WarningState other); }; -std::pair> getInitialWarningState(std::string &flag); +std::pair> getInitialWarningState(std::string &flag); template struct WarningFlag { @@ -150,20 +150,17 @@ std::string Diagnostics::processWarningFlag(char const *flag) { if (!param.has_value() || *param == 0) { param = paramWarning.defaultLevel; } else if (*param > maxParam) { - if (*param != 255) { // Don't warn if already capped - warnx( - "Invalid parameter %" PRIu8 - " for warning flag \"%s\"; capping at maximum %" PRIu8, - *param, - rootFlag.c_str(), - maxParam - ); - } + warnx( + "Invalid warning flag parameter \"%s=%" PRIu32 "\"; capping at maximum %" PRIu8, + rootFlag.c_str(), + *param, + maxParam + ); *param = maxParam; } // Set the first to enabled/error, and disable the rest - for (uint8_t ofs = 0; ofs < maxParam; ofs++) { + for (uint32_t ofs = 0; ofs < maxParam; ofs++) { if (WarningState &warning = state.flagStates[baseID + ofs]; ofs < *param) { warning.update(flagState); } else { @@ -174,7 +171,7 @@ std::string Diagnostics::processWarningFlag(char const *flag) { } if (param.has_value()) { - warnx("Unknown warning flag parameter \"%s\"", rootFlag.c_str()); + warnx("Unknown warning flag parameter \"%s=%" PRIu32 "\"", rootFlag.c_str(), *param); return rootFlag; } diff --git a/src/diagnostics.cpp b/src/diagnostics.cpp index f0df7cf0..c0a64a01 100644 --- a/src/diagnostics.cpp +++ b/src/diagnostics.cpp @@ -18,7 +18,7 @@ void WarningState::update(WarningState other) { } } -std::pair> getInitialWarningState(std::string &flag) { +std::pair> getInitialWarningState(std::string &flag) { // Check for prefixes that affect what the flag does WarningState state; if (flag.starts_with("error=")) { @@ -51,28 +51,22 @@ std::pair> getInitialWarningState(std::stri // Is the rest of the string a decimal number? // We want to avoid `strtoul`'s whitespace and sign, so we parse manually char const *ptr = flag.c_str() + equals + 1; - uint8_t param = 0; - bool warned = false; + uint32_t param = 0; + bool overflowed = false; - // The `if`'s condition above ensures that this will run at least once - do { - // If we don't have a digit, bail - if (*ptr < '0' || *ptr > '9') { - break; - } - // Avoid overflowing! - if (param > UINT8_MAX - (*ptr - '0')) { - if (!warned) { - warnx("Invalid warning flag \"%s\": capping parameter at 255", flag.c_str()); - } - warned = true; // Only warn once, cap always - param = 255; + for (; *ptr >= '0' && *ptr <= '9'; ++ptr) { + if (overflowed) { continue; } - param = param * 10 + (*ptr - '0'); - ++ptr; - } while (*ptr); + uint32_t c = *ptr - '0'; + if (param > (UINT32_MAX - c) / 10) { + overflowed = true; + param = UINT32_MAX; + continue; + } + param = param * 10 + c; + } // If we reached the end of the string, truncate it at the '=' if (*ptr == '\0') { diff --git a/test/asm/diagnostic-parameter-cap.asm b/test/asm/diagnostic-parameter-cap.asm new file mode 100644 index 00000000..f3c824e0 --- /dev/null +++ b/test/asm/diagnostic-parameter-cap.asm @@ -0,0 +1,4 @@ +opt Wtruncation=256 +section "test", rom0 +db 999 +db -254 diff --git a/test/asm/diagnostic-parameter-cap.err b/test/asm/diagnostic-parameter-cap.err new file mode 100644 index 00000000..e9c4fbad --- /dev/null +++ b/test/asm/diagnostic-parameter-cap.err @@ -0,0 +1,5 @@ +warning: Invalid warning flag parameter "truncation=256"; capping at maximum 2 +warning: diagnostic-parameter-cap.asm(3): [-Wtruncation] + Expression must be 8-bit; use LOW() to force 8-bit +warning: diagnostic-parameter-cap.asm(4): [-Wtruncation] + Expression must be 8-bit; use LOW() to force 8-bit diff --git a/test/asm/invalid-param.err b/test/asm/invalid-param.err index f2c6b42f..e92a054f 100644 --- a/test/asm/invalid-param.err +++ b/test/asm/invalid-param.err @@ -1,4 +1,4 @@ -warning: Invalid parameter 99 for warning flag "truncation"; capping at maximum 2 +warning: Invalid warning flag parameter "truncation=99"; capping at maximum 2 warning: invalid-param.asm(2): [-Wtruncation] Expression must be 8-bit; use LOW() to force 8-bit warning: invalid-param.asm(3): [-Wtruncation]