Fix the NMEA checksum offset and harden the buffer writes around it (#11293)

* Checksum NMEA sentences from the $ delimiter

The PositionLite printWPL() format begins with a CRLF, so the fixed start offset of 1 folded the newline and the $ into the checksum and every sentence went out with a wrong value. Locate the $ instead and stop at the terminator or a \*.

* Clamp truncated writes and harden the remaining fixed buffers

snprintf returns the length it would have written, so a truncated NMEA sentence
made buf + len point past the buffer and bufsz - len underflow into a huge size
for the checksum append. Clamp after each write.

Also pulls in the rest of #11236: the two remaining Dropzone sprintf calls, the
dead strcpy in mt_sprintf that wrote one byte past a zero-size allocation for an
empty format, and the 10-byte errcode buffer that INT32_MIN overflows.

Co-Authored-By: Andrew Yong <me@ndoo.sg>

* Bail out on a zero-sized buffer and cast err for %ld

snprintf writes nothing at all when bufsz is 0, not even a terminator, so the
checksum helper would run strchr over whatever the buffer already held. Return
before touching it.

int32_t is not long on every target, so cast before formatting with %ld.

Co-Authored-By: Andrew Yong <me@ndoo.sg>

* Add NMEA sentence regression tests

Covers checksum computation from the $ delimiter for both printWPL
overloads and printGGA, zero-sized buffers, and truncated buffers down
to one byte.

Co-Authored-By: Andrew Yong <me@ndoo.sg>

* Tighten checksum parsing and pin the WPL fixture checksum

Require exactly two hex digits followed by the sentence terminator, and
assert both WPL overloads against a known checksum instead of comparing
them to each other.

* Bump native suite count to 43

---------

Co-authored-by: Andrew Yong <me@ndoo.sg>
This commit is contained in:
Thomas Göttgens
2026-07-31 08:20:56 +00:00
committed by GitHub
co-authored by Andrew Yong
parent 575788ae7b
commit 6367132919
6 changed files with 201 additions and 22 deletions
-1
View File
@@ -386,7 +386,6 @@ std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
va_list ap;
while (1) {
formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
strcpy(&formatted[0], fmt_str.c_str());
va_start(ap, fmt_str);
int final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
va_end(ap);