]> git.vpit.fr Git - perl/modules/Scope-Upper.git/commit
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)
commitf4167ba5f8779b2ae9174431fed29d3e0cd6411e
treec8092e4108ed8f96ff7d58b708c4c97adb2504b6
parent5736d907ca8e5e47a4c2c70564014c8b4ec4f1aa
fix uplevel() under 5.23.8+

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.
Upper.xs