April 19, 2019·4 min read·engineeringperlmaintenancefiles

Perl 5.28.2 fixes completion of in-place edits

Perl 5.28.2 distinguishes successful shutdown from an exception when an in-place edit is still open. The maintenance release also repairs a child-input regression.

Leaving an input loop early can still be a successful edit. Perl 5.28.2 corrects the case where an in-place edit remains in progress during global destruction and the process has a zero exit status. The interpreter now treats that edit as successful and replaces the input file with the output produced. The April 19 release documents this behavior in its versioned maintenance notes.

The distinction matters because ending a loop and failing a program express different intentions. A script can have everything it needs after its first matching record. If leaving the loop prevents the replacement from completing, the visible control flow does not describe the result on disk. This release makes the documented shutdown condition part of deciding whether to complete the replacement.

Perl's in-place editing is particularly relevant to my preference for one-off text work. A short command can change a file without a separate program to manage its output. That convenience makes the interpreter's definition of success part of the command's practical meaning, even when the code consists of only one expression.

Early termination and failure have different results

The release notes illustrate the repair with one command that prints a replacement and leaves the loop, and another that prints the same replacement before raising an exception. Adding an explicit placeholder filename makes their intended invocation clear.

perl -i -ne 'print "Foo"; last' example.txt
perl -i -ne 'print "Foo"; die' example.txt

These are alternatives, not a sequence to run against the same valuable file. The first command can complete the replacement at shutdown. The second does not complete it under the documented error condition. In either command the output consists only of what the program prints. Leaving the loop is not a request to copy the rest of the input unchanged.

The repair is conditional. It applies when the edit is still in progress during global destruction and the exit code stored in $? is zero. The release notes do not claim that every way of interrupting a process commits output. They explain how the interpreter handles this specific finalization state. Treating that as a general guarantee about interrupted file operations would go beyond the fix.

This also distinguishes output production from successful replacement. A program can already have printed data before its final status is known. Perl's decision at shutdown determines whether that produced output becomes the input file's replacement in the case described. The printed text alone is therefore insufficient to infer the eventual file contents.

The maintenance scope is concrete

Perl 5.28.2 describes changes since 5.28.1. Its notes direct users upgrading from 5.28.0 to read the earlier delta as well. That scope is useful because the maintenance release can be evaluated through particular repaired behaviors without attributing unrelated development work to it.

A second fix concerns a regression in Perl 5.28 involving a child process after the parent closes standard input. The notes describe opening a pipe to wc -l after closing STDIN. The child could reach exec with its standard input closed, so the intended pipe was not usable as the child's input. Perl 5.28.2 repairs that regression.

The two fixes concern different resources. In-place editing needs the right completion decision for a file replacement. A pipe to a child needs the correct input descriptor to survive process execution. Both can make a small command fail for reasons that are absent from its text-processing expression. That is why runtime maintenance remains relevant even when a script uses no new language syntax.

I value a maintenance release that identifies those conditions precisely. A general statement about better reliability says little about whether an existing command is affected. The documented early-loop-exit case and child-input regression provide enough detail to relate the release to actual program behavior without inventing a wider claim.

A Unicode correction changes accepted input

The release also changes script-run handling for digits in Unicode's Common script. Earlier behavior recognized ASCII digits in a run associated with another script but overlooked other digit sets in Common. The correction allows those sets too, including the fullwidth digits and mathematical digit sets named in the notes.

That change retains a restriction. All digits in a run must still come from the same set of ten digits. Permitting additional sets does not authorize arbitrary mixing within one run. The release classifies the correction as both a bug fix and an incompatibility because the set of accepted strings changes.

This is a useful reminder that a maintenance version can change observable acceptance rules while preserving the intended design. A caller that depended on the earlier rejection can observe different results. The documented rule provides the explanation, with no need to treat every accepted new input as an unrelated language extension.

Shared-library builds need a different path

On macOS, the release repairs build and test behavior for useshrplib builds under System Integrity Protection. The notes explain that SIP prevents certain binaries, including those in /bin, from receiving DYLD_LIBRARY_PATH. Passing through a shell could therefore lose the variable before a build or test process tried to find libperl.dylib.

The adjusted build initially expects the library in the build directory, then changes the library path during installation to point to the installed copy. This addresses the described loader dependency directly. Together with the in-place edit repair, it gives the maintenance release a specific purpose at two different stages of use. The interpreter can finish a successful early edit, and its shared-library build can locate the runtime library under the platform's environment restrictions.