8088 Commits

Author SHA1 Message Date
Victor Zverovich
e7e6e3f710 Don't lose data on short writes in fmt::ostream
flush ignored the number of bytes written by write which can be less
than requested, silently dropping the rest of the buffer. Write in a loop
until all data is written.
2026-11-08 09:49:35 -08:00
Victor Zverovich
aa2ce7d30d Don't terminate when fmt::ostream fails to write in the destructor
The destructor flushed the buffer and let write errors escape, calling
std::terminate on errors like a full disk. Report the error instead, like
file and buffered_file do on close errors. Also clear the buffer before
writing in flush so that data from a failed write, e.g. in close, is not
written again by the destructor.
2026-11-08 09:16:11 -08:00
Victor Zverovich
bee9426a64 Document that fmt_vformat doesn't null-terminate the output 2026-11-08 08:35:01 -08:00
Victor Zverovich
aa99376370 Don't corrupt the FILE buffer when printing to a non-writable stream
init_buffer decremented the write pointer even when putc_unlocked failed,
turning a null pointer into (char*)-1 that print then wrote through, e.g.
when printing to a stream opened for reading. Report an error instead.
2026-11-08 08:29:42 -08:00
Terry Golubiewski
e3d10c994d fix: avoid null pointers in zero-length string comparisons (#5014)
Return zero from detail::compare when n == 0. Sanitizer checking reported
null pointers being passed to memcmp when comparing empty string views,
even though the comparison length was zero.
2026-11-08 08:10:13 -08:00
Victor Zverovich
ded661bf35 Move FMT_USE_RTTI to ostream.h
Only ostream.h and std.h use it, and std.h includes ostream.h.
2026-11-08 07:23:41 -08:00
Victor Zverovich
41f2838233 Remove test-only code from the headers and move equal2 to format-inl.h
Its only user is vformat_to, which needs only the char overload.
2026-11-08 06:37:50 -08:00
Ivan Lazarić
32777676cf
Fixup range formatting to match stdlib (#5005)
* Fixup range formatting to match stdlib

fmt would format a range of characters with `{:s}`
spec with surrounding quotes, whereas stdlib omits the quotes.
This patch drops the quotes.

* update docs
2026-11-08 06:33:02 -08:00
Shawn
9c19ea4664
Fix precision formatting of long double values just below a power of 10 (#5010)
* Fix precision formatting of long double values just below a power of 10

format_dragon included the upper boundary when checking whether the
estimated exponent is one too high. This is needed for the shortest
output, but with a given precision it left a leading zero digit, so
values such as nextafter(1e43L, 0) were printed with an extra digit in
fixed notation or a mantissa below 1 in exponent notation.

* Apply clang-format
2026-11-07 19:25:38 -08:00
Victor Zverovich
d102a01edf Truncate "(null)" to the precision and print null pointers as 0x0
Printing nothing for a small precision hides the null, and other libc
implementations truncate too. 0x0 matches fmt::format and std::format.
2026-11-07 19:04:02 -08:00
Victor Zverovich
1b5222af1b Clarify ostream capacity comment and strengthen zero buffer test
The old test only caught the overflow under ASan.
2026-11-07 16:51:20 -08:00
Victor Zverovich
a9e41a6df2 Rename rep to abs_rep in duration_formatter and simplify the tests
The old name differed from Rep only in case, which made the narrowing
fixed in #5003 easy to miss.
2026-11-07 15:42:47 -08:00
aizu-m
3a52eb4f1d
fix null pointer arithmetic for %s with precision in vprintf (#5001)
* fix null pointer arithmetic for %s with precision in vprintf

* Match glibc for null %s with a precision
2026-11-07 14:41:17 -08:00
Victor Zverovich
d93446e3dd Fix shifting the fallback uint128 by zero
A shift of 0 evaluated lo_ >> 64 or hi_ << 64, which is undefined.
2026-11-07 13:44:54 -08:00
Victor Zverovich
b2b9b074d4 Simplify hexfloat rounding and test long double ties
Avoids shifting by zero, which is undefined for the fallback uint128.
The float tie test duplicated the double one; floats format as doubles.
2026-11-07 12:58:14 -08:00
Victor Zverovich
dcdef1b80e Avoid 128-bit division when formatting 128-bit integers
Division by 10^19 compiled to a slow __udivti3 call. A reciprocal, as
suggested in #5006, makes 128-bit formatting ~1.8x faster on arm64.
2026-11-07 11:27:35 -08:00
Victor Zverovich
24ab1de71c Document why the SLSA generator is referenced by tag
Scorecard flags the tag as an unpinned dependency, but the generator
doesn't support being pinned by hash.
2026-11-07 09:34:40 -08:00
Victor Zverovich
31a44d5a83 Bump version 2026-11-07 09:34:40 -08:00
Victor Zverovich
cfa163aea8 Update changelog 2026-11-07 09:34:40 -08:00
aizu-m
4daaa87b86
fix heap overflow in fmt::ostream with buffer_size = 0 (#5011)
output_file(path, buffer_size = 0) allocated a zero-size buffer, but
ostream::grow can only make room by flushing, so a zero capacity is never
increased. push_back then writes past the allocation and leaves size()
above capacity(), after which append computes capacity_ - size_ as
SIZE_MAX and copies the rest of the output out of bounds. If the first
write is an append instead, the count is clamped to 0 and print never
returns.

Allocate at least one byte so a zero buffer size behaves like 1.
2026-11-07 09:14:57 -08:00
Victor Zverovich
73b747233e Ignore __pycache__
This also keeps it out of the source package.
2026-11-07 08:53:07 -08:00
Victor Zverovich
5750f9d0f4 Reuse size_padding for localized integers and simplify the test
Both integer writers now compute zero padding the same way.
2026-11-07 07:55:27 -08:00
Victor Zverovich
080b1d0219 Avoid a path string copy and move wide path tests to xchar-test
FMT_STATIC_THOUSANDS_SEPARATOR has had no effect since 11.1.0, so drop
its guard.
2026-11-07 07:27:07 -08:00
khan
47fcd357ab
Avoid narrowing duration day counts to the original representation (#5003)
* Avoid narrowing duration day counts to the original representation

* Keep duration field values in the promoted representation

---------

Co-authored-by: Aikhan Jumashukurov <117706338+aikhanj@users.noreply.github.com>
2026-11-06 15:44:43 -08:00
Eminy
9e7aaa3f27
Round hexfloat ties to even like printf (#5002) 2026-11-06 12:52:29 -08:00
Victor Zverovich
b1397ab7bc Fix valueless variant output and simplify literals in std.h
The catch block dropped the iterator returned by write, so the text
was lost when formatting into a pointer with FMT_COMPILE.
2026-11-06 11:35:06 -08:00
Ngo Quoc Viet
6864349b74
Fix generic path format when formatting to wide strings (#4999)
* Fix generic path format when formatting to wide strings

get_path_string used the native or generic string computed by the path
formatter only when converting wchar_t to UTF-8 and fell back to
p.string<Char>() otherwise, so the 'g' specifier was ignored when the
output character type matched path::value_type. On Windows,
fmt::format(L"{:g}", path(L"C:\\foo")) returned L"C:\\foo" instead of
L"C:/foo". Use the passed string in that case, as write_escaped_path
already does.

* Keep generic path format when converting to wide strings on POSIX
2026-11-06 10:08:34 -08:00
Marvel Harisson
7f7a16a131
Fix wide formatting of variant, monostate and expected (#4991)
The formatters for std::variant, std::monostate, std::expected and
std::unexpected wrote narrow string literals with detail::write<Char>,
which is ambiguous for wchar_t, so formatting these types into a wide
string failed to compile even though is_formattable reported them as
formattable. Use detail::string_literal like the std::optional
formatter does.
2026-11-06 09:57:48 -08:00
Victor Zverovich
7690aa5574 Simplify float to integral duration_cast and its tests
Compute the upper bound as 2^digits with std::ldexp instead of
static_cast<FromRep>(max) + 1, which is only exact when rounding to
nearest: with FE_UPWARD in an unoptimized build the bound became
2^63 + 2048 and a count of 2^63 reached the undefined conversion.
Truncate the count once and use it for both the check and the cast.

Skip the checks that need safe duration casts when
FMT_SAFE_DURATION_CAST is 0, where the NaN time point check failed.
Drop the 1e300 time point and two bool assertions, which don't catch
anything the others don't, and test max + 1 and NaN directly.
2026-11-06 09:43:42 -08:00
aizu-m
4ed3535092
Fix unchecked float to integral conversion in detail::duration_cast (#4985)
* fix unchecked float to integral conversion in detail::duration_cast

* Check the truncated count in float to integral duration_cast

* Keep the duration_cast fallback for custom representations

* Use an explicit rep in the custom_rep duration_cast test

std::chrono::seconds is duration<long> on 64-bit Linux so common_type<long,
custom_rep> had no specialization and chrono-test failed to compile there.

* Exclude bool from the checked float to integral duration_cast
2026-11-01 09:10:37 -08:00
dependabot[bot]
3ce0db1511
Bump ossf/scorecard-action from 2.4.2 to 2.5.0 (#5008)
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.2 to 2.5.0.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](05b42c6244...fa7117db83)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-01 07:52:04 -08:00
Nathan Chandrasekar
09a606d17a
Fix zero padding for localized integers (#4994) 2026-10-31 10:15:44 -07:00
Victor Zverovich
dc4675a400 Simplify floating-point 12-hour test 2026-10-31 08:38:20 -07:00
Nathan Chandrasekar
92d2c541e3
Fix 12-hour formatting of floating-point durations (#4988) 2026-10-31 08:27:00 -07:00
Victor Zverovich
8362a1be15 Reduce code size of hexfloat formatting
Move writing of the formatted hexfloat into write_hexfloat, which only
depends on the character and iterator types, so that it is not duplicated
for each floating-point type, and mark decimal_point_impl noinline to
avoid inlining the std::locale lookup into every caller.
2026-10-30 13:03:19 -07:00
Victor Zverovich
97bd2ad530 Simplify ISO week computation
Compute the ISO week-based year and week number from the day of the year
of the Thursday in the current week instead of the weekday of December 31.
This only needs a leap year check, which works for negative years without
floored division, and is about 3 times faster.

For std::tm values with tm_wday and tm_yday inconsistent with tm_year,
%G, %g and %V now give the same results as strftime.

Replace the negative year tests with a year_month_day test that also
covers the leap year check and days_from_civil for negative years.
2026-10-30 11:53:17 -07:00
Victor Zverovich
f87a75e152 Clean up duration_formatter and simplify duration sign tests 2026-10-25 09:34:12 -07:00
Marvel Harisson
2e60743c67
Fix formatting of nullptr with FMT_COMPILE and to_string (#4993)
* Fix formatting of nullptr with FMT_COMPILE and to_string

std::nullptr_t is implicitly convertible to string_view and const char*,
so compiled format strings and fmt::to_string treated nullptr as a null
C string: FMT_COMPILE("{}!") crashed and FMT_COMPILE("{}") and to_string
threw "string pointer is null". Format it as a pointer ("0x0") like the
runtime API does.

* Write nullptr as a pointer in detail::write

detail::write<Char>(out, nullptr) picked the const Char* overload, so
fmt::to_string(nullptr) and FMT_COMPILE("{}") threw "string pointer is
null". Add a nullptr_t overload that forwards to the const void* one.
2026-10-25 09:30:45 -07:00
aizu-m
3a2dcb59ef
Don't truncate output size to int in fmt_vformat and vfprintf (#4987)
* Don't truncate output size to int in fmt_vformat and vfprintf

* Check size before writing in vfprintf
2026-10-25 09:17:26 -07:00
Marvel Harisson
88a0ae2020
Use the locale decimal point in localized hexfloat formatting (#4992)
With the L flag, floating-point values are formatted with the locale's
decimal point, but the hexfloat presentation ('a'/'A') always emitted
'.'. Replace it with the locale decimal point when the value is
localized, like the other floating-point presentations do.
2026-10-24 11:15:30 -07:00
Mohith
434e30f81f
Fix signs in floating-point duration formatting (#4981) 2026-10-24 10:28:23 -07:00
Victor Zverovich
a8293b774e Bump certifi to 2026.10.23 2026-10-24 10:17:28 -07:00
Victor Zverovich
6b528261ec Fix allocation size overflow in detail::allocator
allocator<T>::allocate(n) computed n * sizeof(T) with only an FMT_ASSERT
guarding against overflow, which is a no-op under NDEBUG. On 32-bit targets
a width of 2^30 or more with a 4-byte character type, e.g.
fmt::format(L"{:>{}}", s, 1100000000), wraps the byte count around, and
basic_memory_buffer records a capacity much larger than the block it got,
so padding is written past the end of the allocation.

Make the check unconditional and throw std::bad_alloc, as std::allocator
did before it was replaced in 11.1.0. Move <new> back to format.h since the
header now throws std::bad_alloc.
2026-10-24 10:03:53 -07:00
DeviousCardi
011e5a911f
Fix ISO week number and year for negative years (#4989)
iso_year_weeks computed the weekday of December 31 with truncating
division and a remainder that is negative for negative years, so it
returned the wrong number of ISO weeks for years before year 0. As a
result %V and %G/%g were wrong around the start and end of such years,
e.g. 1 January of year -1 was formatted as week 52 of year -2 instead
of week 53, and 31 December of year -2 as week 1 of year -1.

Use floored division and a non-negative remainder.


Claude-Session: https://claude.ai/code/session_01Y1b55sEL1gA1c3FCMcQCbm

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 09:59:35 -07:00
fhgffy
0fc31633e7
Fix weekday and day of year when formatting year_month_day (#4978)
The year_month_day formatter only filled in tm_year, tm_mon and tm_mday,
so specifiers that depend on the weekday or the day of the year (%a, %A,
%u, %w, %j, %U, %W, %V, %G, %g) were formatted from zero-initialized
fields, e.g. every date was printed as a Sunday. Compute tm_wday and
tm_yday from the date before passing it to the tm formatter.
2026-10-18 07:14:35 -07:00
Mayank Jaiswal
89a7f4a7ca
Fix FMT_COMPILE with ranges, tuples and maps (#4974)
nested_format_specs::write formatted the body of a padded value into a
temporary buffer using a context of the same type as the outer one. This
only works when the outer context writes to an appender, so FMT_COMPILE
and format_to with other output iterators failed to compile even when no
width was given.

Use a buffer context that takes arguments and locale from the outer
context when the outer context doesn't write to an appender.

Fixes #4949.
2026-10-18 07:11:07 -07:00
Victor Zverovich
4ded41f186 Simplify pre-epoch local_time formatting
Floor the seconds before calling gmtime instead of adjusting tm_sec, and
keep the subsecond remainder in the common duration type, which fixes
overflow for narrow reps such as duration<int16_t, std::micro>.
2026-10-18 07:02:27 -07:00
Kartikey Negi
6ba294f5a6
Fix subsecond formatting for pre-epoch local_time (#4975) (#4976) 2026-10-18 06:45:15 -07:00
Victor Zverovich
18164eaf8b Simplify printf flag tests
The sign is cleared for unsigned conversions regardless of whether the
'+' or the space flag was given, so "% o" and "% X" only repeat what
"%+o" and "%+X" already cover.
2026-10-17 07:16:33 -07:00
fhgffy
01bef95d34
Ignore '+' and space flags for unsigned printf conversions (#4977)
C only applies the '+' and space flags to signed conversions, so
fmt::sprintf("%+u", 42) should give "42" like printf does, not "+42".
The same goes for %o, %x and %X.
2026-10-17 07:11:43 -07:00