lib: snprintf_can_error_frame: document and check required buffer size

The helper functions for the error frame content added the return
values of snprintf() to the buffer offset without checking for
truncation. With a too small buffer the following 'len - n' calculation
wrapped around (size_t) and subsequent snprintf() calls could write
beyond the end of the buffer.

As the maximum output length is known, introduce CANERR_BUFFSZ in lib.h
with a description how the required buffer size is calculated and
return an empty string if the provided buffer is smaller. The only user
candump provides a buffer of more than 6000 bytes for this function.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
This commit is contained in:
Oliver Hartkopp
2026-10-14 11:15:54 +02:00
parent 6bdb574707
commit 411a68675f
2 changed files with 29 additions and 2 deletions
+8
View File
@@ -664,6 +664,7 @@ int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view)
return offset; return offset;
} }
/* check CANERR_BUFFSZ in lib.h when changing the error frame strings */
static const char *error_classes[] = { static const char *error_classes[] = {
"tx-timeout", "tx-timeout",
"lost-arbitration", "lost-arbitration",
@@ -844,6 +845,13 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
if (!sep) if (!sep)
sep = defsep; sep = defsep;
/* the size of the provided buffer has to fit CANERR_BUFFSZ (see lib.h) */
if (len < CANERR_BUFFSZ) {
if (len)
buf[0] = 0; /* empty terminated string */
return 0;
}
for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) { for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
mask = 1 << i; mask = 1 << i;
if (class & mask) { if (class & mask) {
+21 -2
View File
@@ -238,11 +238,30 @@ int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view);
* data bytes is limited to 64 to fit terminal output use-cases. * data bytes is limited to 64 to fit terminal output use-cases.
*/ */
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
const char *sep);
/* /*
* Creates a CAN error frame output in user readable format. * Creates a CAN error frame output in user readable format.
*
* buf: buffer for the output string
* len: size of the provided buffer buf in bytes (incl. string termination)
* sep: separator string between the error classes (NULL => default ",")
*
* The buffer size len needs to be at least CANERR_BUFFSZ bytes - otherwise
* an empty string is returned.
*
* Calculation of the required buffer size:
* The longest error frame content (all error classes and details set) has
* 465 characters plus the string termination = 466 bytes. Additionally up
* to 9 separators are inserted which results in 466 + 9 * strlen(sep) bytes,
* e.g. 466 + 9 * 2 = 484 bytes for "\n\t" (as used in candump).
* With CANERR_BUFFSZ = 800 the separator must not exceed 37 characters.
*
* When the error frame content (the strings in lib.c) is changed, the current
* values have to be re-calculated and CANERR_BUFFSZ has to be adapted if needed.
*/ */
#define CANERR_BUFFSZ 800
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
const char *sep);
/** /**
* timespec_diff_ms - calculate timespec difference in milliseconds * timespec_diff_ms - calculate timespec difference in milliseconds