May 30, 2017·6 min read·engineeringperlsecuritymodulessyntax

Perl 5.26 makes module locations explicit

Perl 5.26 removes the current directory from the default module search path. Its compatibility controls explain why a successful CPAN build can conceal a runtime dependency on the old behavior.

An optional dependency can become a code-execution decision merely because of the directory in which a program starts. Perl's historical default includes . as the last entry in @INC, so a missing installed module can lead the interpreter to search its working directory. Perl 5.26 removes that default entry. Its release notes use an untrusted directory such as /tmp to explain the risk. The history included in the distribution dates the release to May 30, 2017.

The compatibility problem extends beyond scripts that deliberately load local modules. Distribution build files and test programs can also rely on that search. A module can build under a compatibility setting and then fail after installation, when the application uses the new default. Understanding which process has which search path is therefore more useful than treating the update as a single missing-directory error.

I value Perl for concise text work, where a short expression can perform matching and substitution without a separate library interface. A safer loading default supports that use. The interpreter should not silently give the launch directory responsibility for satisfying executable dependencies merely because a script needs to process files there.

The old behavior mixed two kinds of location

The installed interpreter provides a default set of paths in @INC. Historically, it also appended the current directory unless taint mode was enabled with perl -T. That exception already recognized that a working directory can be an unsuitable place to discover code. Version 5.26 makes exclusion the default outside taint mode as well.

The change does not prohibit local code. It requires the program or its environment to express where that code is meant to come from. A trusted module directory and the process's current directory are different concepts, even if a particular invocation makes them coincide. A script launched against a different set of input files should not automatically gain a different library source.

The distinction is especially important for optional modules. A program may be prepared to continue when a dependency is absent, but a successful load still executes the selected code. Catching a missing-module error cannot protect against finding an unwanted module first. Restricting the default search addresses the selection before the program reaches its fallback behavior.

The notes emphasize that do "file.pl" also searches @INC. Many programs use this form for Perl configuration files, and a bare filename previously reached the working directory through its default entry. A new deprecation warning explains when a failed do would have found the file if . had been present.

When the current directory is deliberately the source, the release documents an explicit relative path. Its prefix selects a local file without depending on the default search entry:

do "./foo_config.pl";

That expression names the intended location. It still executes the selected file as Perl code, so it is appropriate only when the caller intends to trust that file. Adding the prefix makes the dependency visible. It does not turn a writable directory into a controlled configuration source.

For a script that runs in an untrusted working directory, the release instead discusses full paths, including a configuration file under the user's home directory. The useful question is where the intended configuration lives. Restoring a broad search rule can make the symptom disappear without answering that question.

The compatibility variable changes startup

The interpreter recognizes PERL_USE_UNSAFE_INC. If its value is 1 at startup, Perl appends . to @INC, except under tainting. The release describes this as a temporary compatibility measure. Its effect applies to the interpreter process that reads it, so the environment becomes part of the explanation for any difference between two invocations.

There is also a build-time escape. Unsetting default_inc_excludes_dot through Configure -Udefault_inc_excludes_dot produces an interpreter with the older default. The notes explicitly warn that this restores the associated security concerns. A locally rebuilt interpreter can therefore have a different initial loading policy from the release's normal configuration.

These controls operate at different stages. The configuration option changes how the binary is built. The environment variable changes a particular process at startup. An investigation that records only the Perl version can miss either difference, even though both affect whether a bare module lookup reaches the working directory.

I prefer the new default because it reduces an implicit dependency on how a program was launched. The compatibility controls are useful for understanding old software, but their names and documented warnings accurately identify the trust relationship they restore. They should not be mistaken for a requirement that every installation retain the previous behavior.

A successful build can hide an installed failure

The cpan utility and Test::Harness currently set the compatibility variable to ease installation of distributions that have not adapted. This can make build and test code work when it loads files from the extracted distribution directory. It also creates a difference between that environment and the installed program's environment.

The release notes call out the resulting failure explicitly. A distribution may pass its tests with PERL_USE_UNSAFE_INC=1, install successfully, and then fail when an application loads it without that setting. The tests have exercised the old search policy. Their success says little about a runtime path that depends on the new default.

For module authors, the notes recommend exercising the build with the variable explicitly disabled. They also discourage globally adding . from a library, because doing so changes the caller's policy and can hide accidental dependencies. A library that adjusts the process-wide list to make its own configuration lookup work can expose unrelated subsequent lookups to the working directory.

The documented alternatives include explicit filenames and moving required files into a subdirectory that is deliberately added to the search list. These approaches describe the required location more accurately. Build helpers can identify their own inputs without asserting that every file in the launch directory should be eligible to satisfy a missing module.

Lexical subroutines become ordinary syntax

The release also removes the experimental status of lexical subroutines, introduced in version 5.18. Using them no longer emits the experimental warning. The lexical_subs feature declaration has no effect, and lexical subroutines are available regardless of the feature declarations in scope. Existing code that suppresses the former experimental warning continues to work.

This is a different kind of compatibility change. The module-loading update makes an implicit location unavailable by default, while this change makes an existing language construct available without an opt-in. Both affect what a small program needs to declare, but the release notes give each a separate contract. Removing a warning suppression is not the same migration task as correcting a dependency path.

Indented here-documents add another concrete improvement for source readability. The new ~ modifier strips the whitespace that appears before the closing delimiter from each content line. Newlines remain unchanged, and a line without the required initial whitespace is an error. The delimiter's indentation therefore defines a prefix, rather than asking Perl to guess how much indentation looks appropriate.

The example in the release places the delimiter and content inside a conditional block. Both carry the prefix that Perl removes:

if (1) {
  print <<~EOF;
    Hello there
    EOF
}

It prints Hello there followed by a newline without the leading spaces. The source can align with its surrounding block while the produced text has a different indentation. The exact prefix rule also explains why a less-indented content line is an error instead of being silently left alone.

Regex readability has explicit limits

The new /xx modifier extends /x by generally ignoring spaces and tabs inside bracketed character classes. This allows spacing that would otherwise change the members of the class. The release also introduces clearer capture-variable names, including @{^CAPTURE} for the most recent match's numbered captures. Those values remain dynamic, so retaining them beyond the match's lifetime requires copying them.

Literal left braces require separate attention. The release tightens the rules for unescaped { in regex patterns, but its notes describe both deferred enforcement for previously missed warnings and contexts that remain unambiguous literals. Saying that every unescaped brace now fails would overstate the change. Escaping a literal brace is always valid and avoids relying on those contextual exceptions.

For text programs, these details matter at different points in execution. Spacing and brace rules affect how a pattern is parsed. Capture variables expose the result of a match and retain its dynamic lifetime. A script adopting the new syntax still needs to preserve capture values explicitly when later matching would otherwise replace the result it intends to keep.