From 453f2c52d29143af71436c7c7add52edc9af3bf3 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 25 Feb 2025 21:58:22 -0500 Subject: 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. --- src/nvim/strings.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 818e67b32d..322b97d6bf 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1668,8 +1668,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': @@ -1793,6 +1791,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) { -- cgit