Skip to content

stdlib format improvements - #11502

Open
dgud wants to merge 6 commits into
erlang:masterfrom
dgud:dgud/stdlib/format-improvements
Open

stdlib format improvements#11502
dgud wants to merge 6 commits into
erlang:masterfrom
dgud:dgud/stdlib/format-improvements

Conversation

@dgud

@dgud dgud commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Fixes AI findings.
Use OTP-20232.

dgud added 4 commits August 17, 2026 13:50
indentation_bin/5 used N as an absolute byte offset but passed it
to binary:part/3 as a segment length. This caused a badarg crash
when a binary containing a tab was passed to indentation/2, which
happens via fwrite_bin when ~ts precedes ~p.

Additionally, the newline clause reset N to 0 without updating
Start, causing wrong indentation after multiple newlines.

Fix by making N relative to Start (i.e. the segment length).
A negative precision passed via ~.* (e.g. io_lib:format("~.*c", [-1, $a]))
would cause infinite recursion in chars/2 since -1 bsr 1 = -1.
Other controls (~.*f, ~.*s, etc.) would crash with function_clause.

Fix by validating precision >= 0 in precision/2, raising badarg
consistently for all controls. This matches C printf semantics
where negative precision via * is defined behavior (treated as
omitted), but Erlang chooses to reject it explicitly.
The latin1 list clause in flat_trunc/3 used lists:flatten + lists:split
which materializes the entire input (O(L)) just to take N chars.
Replace with string:slice/3 which is O(N), matching the existing
unicode clause. Also merge both list clauses into one since
string:slice handles both encodings.
The ?IND macro called list_to_binary(Ind) on every line wrap in the
binary pretty-printer loops (pp_tail_bin, pp_pairs_tail_bin,
pp_fields_tail_bin, pp_binary_bin_ind). Since Ind is constant within
each loop, this re-flattened the same iolist on every sibling element
that wrapped to a new line.

Fix by converting Ind to binary lazily only in the branch that
actually wraps, then threading the binary through subsequent
iterations. The ?IND macro now expects a binary argument directly.
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

CT Test Results

    2 files    100 suites   1h 6m 30s ⏱️
2 310 tests 2 259 ✅ 51 💤 0 ❌
2 731 runs  2 675 ✅ 56 💤 0 ❌

Results for commit 5d1bd8f.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

dgud added 2 commits August 18, 2026 09:14
string_bin_escape_unicode/6 passed all bytes > 127 through without
checking for C1 control characters (U+0080-U+009F). These encode
as 0xC2 0x80-0x9F in UTF-8 and could enable terminal control
injection when rendering untrusted strings.

Fix by matching the specific two-byte C1 sequences and octal-escaping
them, consistent with the list-based write_string path.
Previously, chars_limit only capped the field width for ~s via
limit_field/2. Other controls (~c, ~n, ~~, ~w, ~W, ~e, ~f, etc.)
could allocate unbounded padding that bypassed chars_limit entirely.

Fix by passing chars_limit to build_small/build_small_bin and
applying limit_field to the field width before calling control_small.
Also apply limit_field in control_limited for ~w/~W.

Without chars_limit set, behavior is unchanged.
@dgud
dgud requested a review from RaimoNiskanen August 19, 2026 07:42
@dgud dgud self-assigned this Aug 19, 2026
@dgud dgud added team:PS Assigned to OTP team PS testing currently being tested, tag is used by OTP internal CI labels Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team:PS Assigned to OTP team PS testing currently being tested, tag is used by OTP internal CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant