fix(vim_snprintf): special-case handling of binary format

A binary format spec always expects a corresponding unsigned long long
value. However, that explicit handling didn't get included when porting
the code from Vim, so binary format spec was falling through to the
"unsigned" and "length_modifier = NUL" portion of the code:

        } else {
          // unsigned
          switch (length_modifier) {
          case NUL:
            uarg = (tvs
                    ? (unsigned)tv_nr(tvs, &arg_idx)
                    : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
                                   &arg_cur, fmt),
                       va_arg(ap, unsigned)));
            break;

This incorrectly read an "unsigned" value from an "unsigned long long"
variable, which would produce incorrect results on certain platforms.

(cherry picked from commit 453f2c52d2)
This commit is contained in:
James McCoy
2025-02-25 21:58:22 -05:00
committed by github-actions[bot]
parent 3c57ee079d
commit 28a8d59cc7

View File

@@ -1677,8 +1677,6 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
}
switch (fmt_spec) {
case 'b':
case 'B':
case 'd':
case 'u':
case 'o':
@@ -1802,6 +1800,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
if (ptr_arg) {
arg_sign = 1;
}
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
uarg = (tvs
? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
&arg_cur, fmt),
va_arg(ap, unsigned long long))); // NOLINT(runtime/int)
arg_sign = (uarg != 0);
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {