Audit a Perl 5.8.0 Upgrade for Hash, Unicode and Strict Changes
Use perl581delta(1) as a focused compatibility checklist when moving code from Perl 5.8.0 to 5.8.1. You will find the assumptions most likely to change, run small tests for them, and leave a reproducible record of anything that needs editing. Allow about 20 minutes for a small script and longer for a service with test and deployment tooling.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
This guide assumes a shell, a copy of the application, and permission to run its tests. It does not require root. Make a branch or a separate working copy before editing source. The installed manual on this machine describes the historical 5.8.0 to 5.8.1 change; the installed interpreter is newer, currently Perl 5.38.2. That newer interpreter is useful for checking syntax, but it cannot reproduce every old-runtime detail.
Record the interpreter used by the application, rather than relying on the first perl found in an interactive shell:
command -v perl
perl -V:version -V:archname
Checkpoint: keep this output with the test results. If the application uses a version manager or a service-specific path, repeat the command in that environment.
1. Find output that assumes hash order
Perl 5.8.1 makes hash ordering vary between runs. Hash order was never guaranteed, but older programs often treated stable output from keys, values, each, or Data::Dumper as meaningful. Search for generated files, snapshots, logs, protocol messages, and tests that compare such output byte for byte.
rg -n 'keys\s+%|values\s+%|each\s+%|Data::Dumper|Dumper\(' lib bin t
For a deterministic report, sort the data at the boundary that needs it:
my %settings = (port => 443, host => 'example.invalid');
for my $key (sort keys %settings) {
print "$key=$settings{$key}\n";
}
For Data::Dumper, enable its Sortkeys option. Do not make production code depend on a fixed seed as a repair. For a temporary comparison of old output only, the manual documents this process-wide setting:
PERL_HASH_SEED=0 perl ./bin/export-report
Checkpoint: run the exporter twice without the setting. If the files differ only in member order, fix the exporter or comparison rather than preserving the accidental order.
2. Make Unicode I/O explicit
Perl 5.8.0 silently applied UTF-8 to filehandles when the locale looked like UTF-8. Perl 5.8.1 removes that default. Check scripts that read or write non-ASCII text, especially those whose behaviour changes with LANG or LC_ALL. Decide whether each interface is bytes, a named encoding, or UTF-8, then set it deliberately with PerlIO layers or the documented -C and PERL_UNICODE controls.
LC_ALL=C perl ./bin/import.pl < sample.txt
LC_ALL=en_GB.UTF-8 perl ./bin/import.pl < sample.txt
These commands are a comparison test, not a declaration that either locale is correct for your data. Inspect both the input and output bytes before changing a service. A conversion that appears harmless in a terminal can corrupt a feed or database import.
Checkpoint: add a test containing a character outside ASCII and assert the intended bytes or decoded character. Keep the test close to the filehandle code so a later runtime upgrade does not silently change the contract.
3. Inspect signal handlers before choosing compatibility
Perl 5.8.1 adds an escape hatch from safe, deferred signals. Setting PERL_SIGNALS=unsafe restores immediate handling for a process. That can make a blocking operation easier to interrupt, but it can also reintroduce the corruption and crashes that safe signals were intended to avoid.
Do not set it globally as a troubleshooting reflex. First identify handlers, blocking calls, child-process management, and cleanup code:
rg -n '\$SIG\{|POSIX::SigAction|alarm|system\(|qx|backtick' lib bin t
If a controlled legacy test genuinely requires the old behaviour, scope the setting to that one command and record why:
PERL_SIGNALS=unsafe perl ./t/legacy-timeout.t
Checkpoint: remove the variable after the test. Prefer explicit timeouts and safe signal handling for a long-running service.
4. Fix strict pragma and v-string traps
Perl 5.8.1 rejects the misleading form use strict qw(@ISA) with an unknown strict tag. It never enabled the checks that its appearance suggests. Replace it with an explicit declaration:
use strict;
use vars qw(@ISA);
@ISA = qw(Foo);
Search for the old form before running the complete test suite:
rg -n 'use strict\s+qw\([^)]*[@$]' --glob '*.pl' --glob '*.pm' .
Single-number v-strings before => also change meaning. In 5.8.1, v65 is the string v65, not the ASCII character A. Multi-number forms such as v65.66 remain v-strings. Use quoted keys when the spelling matters:
my %labels = ('v65' => 'literal key');
print $labels{'v65'}, "\n";
Checkpoint: compile the application with warnings enabled, then run its tests using the same interpreter and environment as production.
5. Treat deprecations as migration work
The manual calls out pseudo-hashes, 5.005-style threads, and the $* variable. They are not good candidates for a quiet warning suppression. Replace $* with the /s and /m pattern modifiers, and plan to remove old thread and pseudo-hash usage. A temporary no warnings 'deprecated' can hide noise while a staged migration is underway, but it does not restore removed behaviour.
perl -w -c ./bin/app.pl
prove -l t
Done means
- the application records the exact Perl binary and version used for testing;
- unordered data is sorted where output order is part of an interface;
- Unicode input and output have an explicit, tested encoding decision;
PERL_SIGNALS=unsafeis absent unless a documented legacy test needs it;- old
strictsyntax, ambiguous v-string keys, and named deprecations are fixed or tracked; and - the compile check and full test suite pass in the deployment environment.