Skip to content

libc: the wide printf family aborts on %qd, %D, %O, %U, unknown conversions and a trailing % that FreeBSD formats; fix branch ready #5293

Open

Description

@husseinkad

The wide printf family (swprintf, vswprintf, and snwprintf_s for the plain formats) aborts the guest on four things FreeBSD 11.4 vfwprintf.c formats: the q length modifier (%qd), the %D, %O and %U conversions, an unknown conversion character (%y, %5%), and a format ending in a lone % (swprintf(.., L"100%") returns -1 where FreeBSD stops and returns 3). This is the wide counterpart of #3975, whose fix covers only the narrow FormatWindows path.

Fix branch: https://github.com/husseinkad/AnyPS5/tree/fix/libc-wide-printf-extensions (two commits on a recent main: the change and a follow-up from review; libc/src/FormattingWide.cpp, tests/GuestWideFormatting.cpp with a new CheckFreebsdConversions, and one docs/dev/debt/libc.md line). q means long long, D/O/U are the long forms, an unknown character prints itself with width and the - flag (a surrogate pair prints whole and counts as one character), and a trailing % ends the format. %m, %', $, %l5d, %lqd, %qqd, %lp, %qp and %hq still throw as before, and snwprintf_s keeps rejecting all of these.

Checks:

  • The new cases fail on main (abort, "swprintf q length") and pass with the change; guest_wide_formatting, guest_formatting, guest_standard_stream and file_streams pass.
  • About 3 million random cases per variant against the real FreeBSD 11.4 vfwprintf/vswprintf (with its gdtoa), including surrogate pairs and lone surrogates: 0 regressions (no format that matched FreeBSD on main stops matching); snwprintf_s is identical to main on 700k formats; none of the 10k random formats that worked on main changed output or return value; %D, %O, %U with h, hh, l, ll, j and z and the 100%, a%- and %%% cases match.
  • Three independent reviews. The first two found that snwprintf_s had started accepting q and that a surrogate pair used as an unknown conversion character was split into invalid UTF-16; both are fixed in the second commit. check_conventions.py is clean and pr_overlap.py finds no overlap.

Not fixed here: %#.0O of 0 prints nothing where FreeBSD prints 0 (the existing %#.0o bug, which O inherits); %0% and %010% pad with blanks where FreeBSD zero-pads (listed in the debt entry together with the other unknown-conversion padding), as do %05ls and %05lc; %LD and %Ld, stacked modifiers such as %hz, and flags after the width are rejected; truncation returns -1 without setting EOVERFLOW. Only Windows was built and run.

AI-assisted: yes

Activity

  1. MarcZX10 commented on Oct 13, 2026

    @MarcZX10
    Contributor

    Carried the fix into PR #5303: #5303. Linux guest_wide_formatting and guest_formatting pass (2/2), including the FreeBSD conversion, secure-path, and surrogate cases; conventions pass. The Windows and FreeBSD differential runs in the issue report were not repeated locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions