[libc] scanf: do not count suppressed conversions in the return value scanf_main() incremented the result for every successful conversion except %n, including assignment-suppressed ones ("%*d") and "%%". C requires the number of input items *assigned*. Example: sscanf("12 34", "%*d%d", &x) returned 2 instead of 1; sscanf("420jpeg", "%*d%*[pP]%d", &x) returned 1 without writing x (breaks x264's y4m colorspace/bit depth parsing). Still present in llvm main as of 2026-10. diff --git a/libc/src/stdio/scanf_core/scanf_main.h b/libc/src/stdio/scanf_core/scanf_main.h index f975d85..e1eb5fb 100644 --- a/libc/src/stdio/scanf_core/scanf_main.h +++ b/libc/src/stdio/scanf_core/scanf_main.h @@ -32,9 +32,10 @@ int scanf_main(Reader *reader, const char *__restrict str, cur_section = parser.get_next_section()) { if (cur_section.has_conv) { ret_val = convert(reader, cur_section); - // The %n (current position) conversion doesn't increment the number of - // assignments. - if (cur_section.conv_name != 'n') + // Only assigned items count: not %n (current position), not %% and not + // conversions with assignment suppression ('*', the NO_WRITE flag). + if (cur_section.conv_name != 'n' && cur_section.conv_name != '%' && + (cur_section.flags & FormatFlags::NO_WRITE) == 0) conversions += ret_val == READ_OK ? 1 : 0; } else { ret_val = raw_match(reader, cur_section.raw_string);