Skip to content

Integrate #364–#366 with rename safety, w+ seek and gsub allocation fixes - #368

Merged
akeit0 merged 8 commits into
mainfrom
codex/review-364-366-fixes
Oct 23, 2026
Merged

akeit0 merged 8 commits into
mainfrom
codex/review-364-366-fixes

Conversation

@akeit0

@akeit0 akeit0 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

This integrates #364, #365 and #366 and fixes the remaining problems found during review. Failed renames preserve an existing destination (including a locked Windows source and directory-to-file attempts), w+ writes respect the seek position, and suspended gsub calls retain the pooled async builder.

The branch preserves all three original PR heads as ancestors. Merge with a merge commit, so their commits and authorship remain in the history.

Changes added during review:

  • Use overwrite File.Move on .NET 6/8/10 and File.Replace for existing destinations on .NET Standard 2.1; use Directory.Move for directories. Remove the delete-before-move window.
  • Stop classifying WriteUpdate as append mode; test both w+ and w+b, and retain append-after-seek coverage for a+/a+b.
  • Restore AsyncMethodBuilder to GSub, and report Lua's unfinished capture error for an incomplete capture referenced by a replacement.
  • Add reusable GSubBenchmark cases for literal/capture/position/frontier replacements and synchronous/suspended function and table-index handlers.

Validation on Windows, .NET 8.0.32 (SDK 11 preview):

Performance, median of 7 samples, precompiled scripts, same-thread controlled suspension, tiered compilation disabled for steady JIT code:

Workload main original PRs reviewed branch
64 capture replacements 21.55 µs / 9712 B 4.79 µs / 4592 B 4.74 µs / 4592 B
64 position replacements 16.17 µs / 6784 B 3.67 µs / 3200 B 3.76 µs / 3200 B
suspended function 735 ns / 488 B 790 ns / 744 B 716 ns / 488 B
suspended table __index 745 ns / 488 B 794 ns / 744 B 731 ns / 488 B

The builder fix removes the original #366 regression of 256 B per suspended gsub call. Literal/function paths retain their allocation counts. Frontier-at-end now performs the previously missing replacement (1040 B instead of 840 B), so that allocation change reflects corrected behavior. These are local microbenchmarks, not Unity/Mono/IL2CPP measurements. The .NET Standard replacement path uses same-filesystem File.Replace; cross-volume replacement is not supported there.

The new destination-preservation and unfinished-capture tests were run before the follow-up fixes and reproduced their failures. Both w+ seek/write cases also reproduced the append bug before its fix.

Draft pending maintainer approval to merge.

GitHub CI for head 2f6b81954edbf00a36f0f48222388628fc17f759: Linux runtime tests and repository lint both passed.

billythekidz and others added 8 commits October 22, 2026 15:37
FileSystem.Rename removed the destination file before checking that the
source exists, so a failed os.rename lost the destination's contents.
Check the source first, as rename(2) does. With the data no longer lost,
the part of files.lua that the test harness skipped now runs unmodified.
gsub built the replacement with chained StringBuilder.Replace calls, so a
reference to a missing capture (%2) was silently kept, a bare or unknown
%x was accepted, captured text was rescanned, and NUL characters in
captured text turned into '%'. Replacement strings are now expanded in a
single pass and follow Lua 5.2 (invalid capture index, invalid use of '%'
in replacement string).

%f never matched at the end of the subject because the current character
was required to exist. Lua treats it as '\0' there. %f without a set now
raises "missing '[' after '%f' in pattern".

tests-lua/pm.lua passes and is enabled.
# Conflicts:
#	tests/Lua.Tests/IOTests.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants