]> git.vpit.fr Git - perl/modules/Scope-Upper.git/commitdiff
fix uplevel() under 5.23.8+
authorDavid Mitchell <davem@iabyn.com>
Tue, 17 May 2016 08:23:00 +0000 (09:23 +0100)
committerVincent Pit <perl@profvince.com>
Mon, 30 May 2016 12:35:44 +0000 (14:35 +0200)
The old method of creating a new curstackinfo containing the faked-up
new context stack no longer works. This is because leave_scope() is now
called just prior to each context stack entry popping, and so a destructor
which restores the old context array leaves a dangling pointer.

E.g. pp_leavesub() on 5.23.8 onwards looks something like:

    cx = CX_CUR();
    ....
    CX_LEAVE_SCOPE(cx);

    /* at this point the destructor has been called and the old context
     * stack back been restored; cx now points at freed garbage
    */
    cx_popsub(cx); /* SEGV */

Conversely, now that it's guaranteed that the save stack is always
processed prior to each context pop - regardless of whether its a normal
scope exit or an exception - it allows us to use a simpler method to fake
things up for uplevel(): just temporarily change the types of all the
higher contexts to CXt_NULL so that they won't be seen by caller() etc. On
scope exit the savestack destructor restores the old types, which are then
processed and popped as normal.

As well as setting each entry to CXt_NULL we set a flag,
CXp_SU_UPLEVEL_NULLED (whose bit is currently unused by the perl core)
to indicate that this is a temporarily ignored context.

We then introduce a distinction between logical and physical context stack
indices: functions like UP return a logical index which ignore all the
nulled-out contexts; when such a logical value is passed as an arg to a
function such as localize(), it is first converted back to a real index.

The other main change is how uplevel() doctors the sub's arg list as seen
by caller(): previously this was done by modifying the argarray field of
the context entry for the just-called sub. Since 5.23.8 onwards doesn't
have an argarray field, we instead modify the pad[0] of the running sub
(which is what caller() examines now). Since there's no longer a
possibility of getting argarray and pad[0] out of sync, the special fixups
formerly required in the presence of goto are no longer required.

Rather than rolling our own OP_ENTERSUB op, we just use call_sv()
instead, with a PL_runops pointing to a temporary hook that allows the
args to be fixed up on return from pp_entersub. After that, a normal
runops loop is called.

Since uplevel is so different under 5.23.8, I've split the original
functions into

    su_uplevel_old/su_uplevel_new
    su_uplevel_restore_old/su_uplevel_restore_new

with #defines compiling only one set.


No differences found