File Coverage

blib/lib/Lexical/SealRequireHints.pm
Criterion Covered Total %
statement 4 5 80.0
branch 1 2 50.0
condition n/a
subroutine 3 4 75.0
pod n/a
total 8 11 72.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Lexical::SealRequireHints - prevent leakage of lexical hints
4              
5             =head1 SYNOPSIS
6              
7             use Lexical::SealRequireHints;
8              
9             =head1 DESCRIPTION
10              
11             This module works around two historical bugs in Perl's handling of the
12             C<%^H> (lexical hints) variable. One bug causes lexical state in one
13             file to leak into another that is Cd/Cd from it. This bug,
14             [perl #68590], was present from Perl 5.6 up to Perl 5.10, fixed in Perl
15             5.11.0. The second bug causes lexical state (normally a blank C<%^H>
16             once the first bug is fixed) to leak outwards from C, if it is
17             automatically loaded during Unicode regular expression matching, into
18             whatever source is compiling at the time of the regexp match. This bug,
19             [perl #73174], was present from Perl 5.8.7 up to Perl 5.11.5, fixed in
20             Perl 5.12.0.
21              
22             Both of these bugs seriously damage the usability of any module relying
23             on C<%^H> for lexical scoping, on the affected Perl versions. It is in
24             practice essential to work around these bugs when using such modules.
25             On versions of Perl that require such a workaround, this module globally
26             changes the behaviour of C, including C and the implicit
27             C performed in Unicode regular expression matching, so that it
28             no longer exhibits these bugs.
29              
30             The workaround supplied by this module takes effect the first time its
31             C method is called. Typically this will be done by means of a
32             C statement. This should be done as early as possible, because it
33             only affects C/C statements that are compiled after the
34             workaround goes into effect. For C statements, and C
35             statements that are executed immediately and only once, it suffices
36             to invoke the workaround when loading the first module that will set
37             up vulnerable lexical state. Delayed-action C statements,
38             however, are more troublesome, and can require the workaround to be loaded
39             much earlier. Ultimately, an affected Perl program may need to load
40             the workaround as very nearly its first action. Invoking this module
41             multiple times, from multiple modules, is not a problem: the workaround
42             is only applied once, and applies to everything subsequently compiled.
43              
44             This module is implemented in XS, with a pure Perl backup version for
45             systems that can't handle XS modules. The XS version has a better chance
46             of playing nicely with other modules that modify C handling.
47             The pure Perl version can't work at all on some Perl versions; users
48             of those versions must use the XS. On all Perl versions suffering the
49             underlying hint leakage bug, pure Perl hooking of C breaks the
50             use of C without an explicit parameter (implicitly using C<$_>).
51              
52             =head1 PERL VERSION DIFFERENCES
53              
54             The history of the C<%^H> bugs is complex. Here is a chronological
55             statement of the relevant changes.
56              
57             =over
58              
59             =item Perl 5.6.0
60              
61             C<%^H> introduced. It exists only as a hash at compile time. It is not
62             localised by C, so lexical hints leak into every module loaded,
63             which is bug [perl #68590].
64              
65             The C mechanism doesn't work cleanly for C, because
66             overriding C loses the necessary special parsing of bareword
67             arguments to it. As a result, pure Perl code can't properly globally
68             affect the behaviour of C. Pure Perl code can localise C<%^H>
69             itself for any particular C invocation, but a global fix is
70             only possible through XS.
71              
72             =item Perl 5.7.2
73              
74             The C mechanism now works cleanly for C, so pure
75             Perl code can globally affect the behaviour of C to achieve a
76             global fix for the bug.
77              
78             =item Perl 5.8.7
79              
80             When C is automatically loaded during Unicode regular expression
81             matching, C<%^H> now leaks outward from it into whatever source is
82             compiling at the time of the regexp match, which is bug [perl #73174].
83             It often goes unnoticed, because [perl #68590] makes C<%^H> leak into
84             C which then doesn't modify it, so what leaks out tends to
85             be identical to what leaked in. If [perl #68590] is worked around,
86             however, C<%^H> tends to be (correctly) blank inside C, and
87             this bug therefore blanks it for the outer module.
88              
89             =item Perl 5.9.4
90              
91             C<%^H> now exists in two forms. In addition to the relatively ordinary
92             hash that is modified during compilation, the value that it had at
93             each point in compilation is recorded in the compiled op tree, for later
94             examination at runtime. It is in a special representation-sharing format,
95             and writes to C<%^H> are meant to be performed on both forms. C
96             does not localise the runtime form of C<%^H> (and still doesn't localise
97             the compile-time form).
98              
99             A couple of special C<%^H> entries are erroneously written only to the
100             runtime form.
101              
102             Pure Perl code, although it can localise the compile-time C<%^H> by
103             normal means, can't adequately localise the runtime C<%^H>, except by
104             using a string eval stack frame. This makes a satisfactory global fix
105             for the leakage bug impossible in pure Perl.
106              
107             =item Perl 5.10.1
108              
109             C now properly localises the runtime form of C<%^H>, but still
110             not the compile-time form.
111              
112             A global fix is once again possible in pure Perl, because the fix only
113             needs to localise the compile-time form.
114              
115             =item Perl 5.11.0
116              
117             C now properly localises both forms of C<%^H>, fixing [perl
118             #68590]. This makes [perl #73174] apparent without any workaround for
119             [perl #68590].
120              
121             The special C<%^H> entries are now correctly written to both forms of
122             the hash.
123              
124             =item Perl 5.12.0
125              
126             The automatic loading of C during Unicode regular expression
127             matching now properly restores C<%^H>, fixing [perl #73174].
128              
129             =back
130              
131             =cut
132              
133             package Lexical::SealRequireHints;
134              
135 19     19   267173 { use 5.006; }
  19         102  
136             # Don't "use warnings" here because warnings.pm can include require
137             # statements that execute at runtime, and if they're compiled before
138             # this module takes effect then they won't get the magic needed to avoid
139             # leaking hints generated later. We do need to set warning bits here,
140             # because it is necessary to turn *off* redefinition warnings for the
141             # pure Perl implementation (which can redefine CORE::GLOBAL::require).
142             # Not wanting to encode knowledge of specific warning bits, the only
143             # safe thing to do is to turn them all off.
144 19     19   10007 BEGIN { ${^WARNING_BITS} = ""; }
145             # Also don't "use strict", because of consequences of compiling
146             # strict.pm's code.
147              
148             our $VERSION = "0.011";
149              
150             if("$]" >= 5.012) {
151             # bug not present
152             *import = sub {
153 21 50   21   28149 die "$_[0] does not take any importation arguments\n"
154             unless @_ == 1;
155             };
156 0     0     *unimport = sub { die "$_[0] does not support unimportation\n" };
157             } elsif(eval { local $SIG{__DIE__};
158             require XSLoader;
159             XSLoader::load(__PACKAGE__, $VERSION);
160             1;
161             }) {
162             # Successfully loaded XS. Now preemptively load modules that
163             # may be subject to delayed require statements in XSLoader or
164             # things that it loaded.
165             foreach(qw(Carp.pm Carp/Heavy.pm)) {
166             eval { local $SIG{__DIE__}; require($_); 1; };
167             }
168             } elsif("$]" < 5.007002) {
169             die "pure Perl version of @{[__PACKAGE__]} can't work on pre-5.8 perl";
170             } elsif("$]" >= 5.009004 && "$]" < 5.010001) {
171             die "pure Perl version of @{[__PACKAGE__]} can't work on perl 5.10.0";
172             } else {
173             my $done;
174             *import = sub {
175             die "$_[0] does not take any importation arguments\n"
176             unless @_ == 1;
177             return if $done;
178             $done = 1;
179             my $next_require = defined(&CORE::GLOBAL::require) ?
180             \&CORE::GLOBAL::require : sub {
181             my($arg) = @_;
182             # The shenanigans with $CORE::GLOBAL::{require}
183             # are required because if there's a
184             # &CORE::GLOBAL::require when the eval is
185             # executed (compiling the CORE::require it
186             # contains) then the CORE::require in there is
187             # interpreted as plain require on some Perl
188             # versions, leading to recursion.
189             my $grequire = $CORE::GLOBAL::{require};
190             delete $CORE::GLOBAL::{require};
191             my $requirer = eval qq{
192             package @{[scalar(caller(0))]};
193             sub { scalar(CORE::require(\$_[0])) };
194             };
195             $CORE::GLOBAL::{require} = $grequire;
196             return scalar($requirer->($arg));
197             };
198             *CORE::GLOBAL::require = sub ($) {
199             die "wrong number of arguments to require\n"
200             unless @_ == 1;
201             my($arg) = @_;
202             # Some reference to $next_require is required
203             # at this level of subroutine so that it will
204             # be closed over and hence made available to
205             # the string eval.
206             my $nr = $next_require;
207             my $requirer = eval qq{
208             package @{[scalar(caller(0))]};
209             sub { scalar(\$next_require->(\$_[0])) };
210             };
211             # We must localise %^H when performing a require
212             # with a filename, but not a require with a
213             # version number. This is because on Perl 5.9.5
214             # and above require with a version number does an
215             # internal importation from the "feature" module,
216             # which is intentional behaviour that must be
217             # allowed to affect %^H. (That's logically the
218             # wrong place for the feature importation, but
219             # it's too late to change how old Perls do it.)
220             # A version number is an argument that is either
221             # numeric or, from Perl 5.9.2 onwards, a v-string.
222             my $must_localise = ($arg^$arg) ne "0" &&
223             !("$]" >= 5.009002 && ref(\$arg) eq "VSTRING");
224             # On Perl 5.11 we need to set the HINT_LOCALIZE_HH
225             # bit to get proper restoration of %^H by the
226             # swash loading code.
227             $^H |= 0x20000 if "$]" >= 5.011 && $must_localise;
228             # Compile-time %^H gets localised by the
229             # "local %^H". Runtime %^H doesn't exist prior
230             # to Perl 5.9.4, and on Perl 5.10.1 and above is
231             # correctly localised by require. Between those
232             # two regimes there's an area where we can't
233             # correctly localise runtime %^H in pure Perl,
234             # short of putting an eval frame around the
235             # require, so we don't use this implementation in
236             # that region.
237             local %^H if $must_localise;
238             return scalar($requirer->($arg));
239             };
240             };
241             *unimport = sub { die "$_[0] does not support unimportation\n" };
242             }
243              
244             =head1 BUGS
245              
246             The operation of this module depends on influencing the compilation of
247             C. As a result, it cannot prevent lexical state leakage through
248             a C statement that was compiled before this module was invoked.
249             Where problems occur, this module must be invoked earlier.
250              
251             On all Perl versions that need a fix for the lexical hint leakage bug,
252             the pure Perl implementation of this module unavoidably breaks the use
253             of C without an explicit parameter (implicitly using C<$_>).
254             This is due to another bug in the Perl core, fixed in Perl 5.15.5, and is
255             inherent to the mechanism by which pure Perl code can hook C.
256             The use of implicit C<$_> with C is rare, so although this
257             state of affairs is faulty it will actually work for most programs.
258             Perl versions 5.12.0 and greater, despite having the C hooking
259             bug, don't actually exhibit a problem with the pure Perl version of this
260             module, because with the lexical hint leakage bug fixed there is no need
261             for this module to hook C.
262              
263             =head1 SEE ALSO
264              
265             L
266              
267             =head1 AUTHOR
268              
269             Andrew Main (Zefram)
270              
271             =head1 COPYRIGHT
272              
273             Copyright (C) 2009, 2010, 2011, 2012, 2015, 2016, 2017
274             Andrew Main (Zefram)
275              
276             =head1 LICENSE
277              
278             This module is free software; you can redistribute it and/or modify it
279             under the same terms as Perl itself.
280              
281             =cut
282              
283             1;