develooper Front page | perl.perl5.porters | Postings from August 2016

Re: Alternative Fix for base.pm dot-in-INC mechanic.

Thread Previous | Thread Next
From:
Aristotle Pagaltzis
Date:
August 23, 2016 15:50
Subject:
Re: Alternative Fix for base.pm dot-in-INC mechanic.
Message ID:
20160823155005.GA83213@plasmasturm.org
* Kent Fredric <kentfredric@gmail.com> [2016-08-14 23:36]:
> Presently, localising is done regardless of the presence of a ".",
> making any @INC modification in base.pm impossible, even if the user
> had already removed '.' themselves.

Which is, frankly, disastrous, and haarg pointing it out made me cringe
that I completely missed that implication myself. I am dismayed at the
fact that this nearly went unnoticed.

> And so instead of assuming @INC can be simply reverted to its previous
> state, it uses a scope guard

This is obviously the right(er?) approach.

> and thus tries to effectively localise *only* the absense of '.' by:
>
> a) only adding cleanup logic if $INC[-1]  is in fact '.'
> b) reinserting '.' in the cleanup block on base->import scope exit.

That condition is the one questionable part of the patch, to me. It
currently won’t reinsert '.' if the loaded module modifies the end of
@INC – as riba explained, his thinking was that if that happens, it’s
likely to be an @INC hook meant to notice/catch failed loads, or some
such. So that makes good sense to me.

But it also means loading such a module makes the dot removal permanent.

The opposite strategy would look like this:

    sub base::__inc_guard::DESTROY { ${$_[0]} = '.' }

And then within sub import:

    my $dotty = $INC[-1] eq '.'
        && bless \( $INC[-1] = sub {} ), 'base::__inc_guard';

This takes advantage of the fact that putting `sub {}` in @INC does
nothing. It exploits that to replace the dot with a no-op that it keeps
a ref to, and then uses the ref to replace the no-op with a dot on scope
exit. So this means that the dot is gone during the require, but will be
unconditionally restored to its correct @INC location at scope exit – if
it’s still in @INC – totally regardless of other modifications to @INC.

But, this also means that if you load a module that pushes onto @INC,
then the dot will be restored to a non-final position, so it will no
longer be recognised by the $INC[-1] eq '.' logic and therefore will
not be removed by base.pm again.

So part of the upshot is that there are more situations where the dot
remains in @INC.

However, this means it is less ordering sensitive: both of these cases
will have the same effects:

    # case 1
    use base 'Pushes::Hook::Onto::Inc';
    # ...
    use Pushes::Hook::Onto::Inc;

    # vs

    # case 2
    use Pushes::Hook::Onto::Inc;
    # ...
    use base 'Pushes::Hook::Onto::Inc';

Case 2 is the same under all proposals under consideration: the dot will
be part of @INC permanently after the first `use`.

But case 1 is, well, a mess under the original `local` patch, and saner
but differs from case 2 under riba’s proposed patch. Under my proposal,
both cases behave identically.

Given the probable rarity of this case, I believe that debuggability and
comprehensibility of the behaviour of the system are of greater value to
it than the relative increase in attack surface. (In both senses: rarity
makes it more important to have less special behaviour, and also makes
the increase in attack surface affordable.)

Further, the logic is also simpler overall: there is less conditional
behaviour. This is something I strive for in general, because it makes
things more tractable.

Thoughts?

Regards,
-- 
Aristotle Pagaltzis // <http://plasmasturm.org/>

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About