Audit Perl 5.16 Compatibility Before You Upgrade
Jumping from Perl 5.14 to 5.16 quietly breaks feature declarations, lvalue substr and any XS module that trusted old UTF-8 APIs. This audit walks the code that actually crosses that boundary: feature bundles, Unicode handling, XS extensions and changed runtime behaviour. It is an audit guide, not an instruction to replace the Perl your distribution installed. Allow 20 to 30 minutes for a small application, plus time for its own test suite.
The route
Jump straight to the step you need, or tick off Done means at the end.
The local reference is perl5160delta(1) from the perl-doc package. Its header describes Perl 5.16.0, while the installed interpreter used for the checks here is Perl 5.38.2. The examples confirm syntax and behaviour available in the current interpreter, but the change list is specifically the 5.14 to 5.16 release boundary.
1. Record the interpreter you are testing
Run this as an ordinary user, before anything else:
$ command -v perl
/usr/bin/perl
$ perl -v | sed -n '1,4p'
This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
A passing test under 5.38 is not proof that a 5.16 deployment will behave identically. Use the version your application will actually run, and keep the release notes beside the test results.
Checkpoint
Write down the full perl -v output and the path from command -v. If several Perls are installed, an apparently successful check can simply be testing the wrong one.
2. Make the feature boundary explicit
Perl 5.16 changed version declarations so that use v5.16 disables previously enabled features before applying the new bundle. A later declaration can therefore remove features rather than add to the earlier one. Test in a clean process, because feature state is lexical and an interactive shell can obscure where it came from:
$ perl -e 'use v5.16; print "version declaration accepted\n"'
version declaration accepted
$ perl -e 'use v5.16; use feature "fc"; print fc("Straße"), "\n"'
straße
The second command exercises the new Unicode foldcase function, built for better case-insensitive comparison than a plain lowercase operation. It is not a request to normalise text, transliterate it or change how a file is encoded.
- Review every module that declares a Perl version or calls
use feature. - Watch for code that expects an old bundle to survive a later version declaration; it will not.
- Need the old default feature set? 5.16 adds the
:defaultbundle. - Need no features at all? Use
no feature ':all'.
3. Check eval and substr call sites
Perl 5.16 makes string evaluation more consistent. With the new unicode_eval feature, eval $string treats its input as Unicode. The matching evalbytes function evaluates a byte string. Test code that evaluates generated source, especially anything reading from a file or a network:
$ perl -e 'use v5.16; use feature "unicode_eval", "evalbytes"; eval "print qq(unicode\n)"; evalbytes("print qq(bytes\n)")'
unicode
bytes
Warning
Do not use either form as a substitute for input validation. Evaluating untrusted source is still code execution. The real upgrade task is to decide whether each existing call expects characters or bytes, then add tests for non-ASCII input and for the error path reported by $@.
Also audit lvalue substr. In 5.16, the offsets in a returned lvalue are retained until that lvalue is read or modified, so a negative offset can end up pointing at a different position if the original string changes length first. That is an incompatible behaviour change: search for assignments through a substr lvalue and test them after the source string changes.
use v5.16;
my $text = 'abcdef';
my $part = substr $text, -2, 1;
$text = 'longer text';
$part = 'X';
print "$text\n";
The right fix depends on the intended semantics. If the position should be fixed at call time, calculate and copy the value before changing the source string. Do not assume a clean compile preserves the old result.
4. Review Unicode and locale assumptions
The release notes cover almost all of Unicode 6.1, new property aliases, Script_Extensions, Unicode symbol names and better mixing of locales with Unicode. Any test that compares property names or character categories deserves a second look; Unicode 6.1 also changed some character properties and the behaviour of \X for some Thai and Lao characters.
For new code, use Perl's documented Unicode APIs rather than reading files under the interpreter's lib/unicore directory. The notes deprecate direct database-file access and point callers towards Unicode::UCD. That matters for deployment checks: a path that exists in one Perl installation is not a stable interface for another.
5.16 also adds use locale ':not_characters', which leaves locale handling in place except for character-set assumptions. Test this only where the application genuinely combines locale-sensitive operations with UTF-8 data, and record LC_ALL, LC_CTYPE and LANG alongside the test result, since a locale setting is process state.
5. Audit XS and security-sensitive code
If the application has XS modules, this is the highest-value part of the review. The old is_utf8_char(), utf8_to_uvchr() and utf8_to_uvuni() APIs can read beyond the end of malformed input, because their interfaces do not carry enough buffer-length information. Perl 5.16 adds buffer-aware alternatives: is_utf8_char_buf(), utf8_to_uvchr_buf() and utf8_to_uvuni_buf().
Search extension source, generated bindings and vendored modules:
$ rg -n 'is_utf8_char|utf8_to_uvchr|utf8_to_uvuni' path/to/project path/to/local/modules
Replace an old call only after checking its arguments and return handling against the installed Perl headers and API documentation. Then build with warnings enabled and run malformed UTF-8 tests. Do not silence the deprecation warning or treat a clean build as proof that length handling is correct.
Warning
The same release fixes a File::Glob::bsd_glob() memory error when an unsupported GLOB_ALTDIRFUNC flag came from external input. Do not pass flags from configuration or a request directly into globbing APIs without checking the supported values.
6. Exercise incompatible changes before deployment
Read the release notes' incompatible-changes section against your code, rather than scanning only the headline features. Useful searches include special blocks such as BEGIN and END, regexp objects under no overloading, removed XS typemap entries, deprecated Unicode properties, PID and UID variables, and code relying on the old quotemeta behaviour.
$ rg -n 'BEGIN|CHECK|INIT|UNITCHECK|END|no overloading|quotemeta|GLOB_ALTDIRFUNC|is_utf8_' lib bin t xs
$ prove -lr t
Use your project's normal test command if it is not prove. Do not run tests as root to hide permission failures. No step in this guide needs elevated privileges, and changing the system Perl or rebuilding it is outside the safe scope of a compatibility audit.
Done means
- Recorded the exact interpreter used for testing, executable and version.
- Made version declarations and feature bundles an intentional, tested boundary.
- Tested eval, evalbytes and lvalue substr call sites against their actual data model.
- Reviewed Unicode property, locale and lib/unicore assumptions.
- Stopped XS code relying blindly on length-unsafe UTF-8 APIs.
- Ran the full application test suite without changing privileges or the system interpreter.