Appends are ATOMIC: a field is emitted only if the WHOLE serialized form * fits (with PP_ESC_SPACE bytes reserved for the closing '}' + NUL). Cutting a * field mid-value produced unterminated strings/arrays — malformed properties * JSON that aborts every json_extract()-based consumer downstream (seen on the * Linux kernel: 50-param functions truncated at the 2 KB cap). Dropping an * oversized
| 384 | * oversized optional field whole keeps the JSON valid. Twin of |
| 385 | * pass_definitions.c — keep both in sync. */ |
| 386 | static void append_json_string(char *buf, size_t bufsize, size_t *pos, const char *key, |
| 387 | const char *val) { |
| 388 | if (!val || val[0] == '\0') { |
| 389 | return; |
| 390 | } |
| 391 | size_t required = strlen(key) + pp_json_escaped_len(val) + PP_JSON_FIELD_OVERHEAD; |
| 392 | if (*pos + required + PP_ESC_SPACE > bufsize) { |
| 393 | return; /* whole field would not fit — skip it atomically */ |
| 394 | } |
| 395 | size_t p = *pos; |
| 396 | int w = snprintf(buf + p, bufsize - p, ",\"%s\":\"", key); |
| 397 | if (w <= 0 || (size_t)w >= bufsize - p) { |
| 398 | return; |
| 399 | } |
| 400 | p += (size_t)w; |
| 401 | for (const char *s = val; *s && p < bufsize - PP_ESC_MARGIN; s++) { |
| 402 | int n = json_escape_char(buf + p, bufsize - p - PP_ESC_SPACE, *s); |
| 403 | p += (size_t)n; |
| 404 | } |
| 405 | if (p < bufsize - SKIP_ONE) { |
| 406 | buf[p++] = '"'; |
| 407 | } |
| 408 | buf[p] = '\0'; |
| 409 | *pos = p; |
| 410 | } |
| 411 | |
| 412 | /* Append a JSON array of strings: ,"key":["a","b","c"]. Atomic like |
| 413 | * append_json_string: emitted only if the whole array fits. */ |
no test coverage detected