lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

在 2015/5/19 0:32, Philipp Janda 写道:

Is it supported to enumerate/query the local variables of a function from within a return hook?

local variables are scoped; as I understand, the when the return hook get called, it still _within_ the
returning function. the manual says []:

  The return hook:  is called when the interpreter returns from a function.
                    The hook is called *just before* Lua leaves the function.
                    There is no standard way to access the values to be returned by the function.

I have some difficulties on all Lua versions since 5.1:

Lua 5.1:

    func    a    10
    func    b    table: 0x18338e0
    func    c    function: 0x182e890
    func    d    true
    func    e    string

(apparently all locals are already gone).

Lua 5.2:

    func    a    10
    func    b    table: 0x1b3ed10
    func    c    function: 0x1b3f4c0
    func    d    true
    func    e    string

    HOOK    a    table: 0x1b3fbc0
    HOOK    b    function: 0x1b3c850
    HOOK    c    3
    HOOK    d    c
    HOOK    e    c

(local variable names are still there, values are wrong)

Lua 5.3:

    func    a    10
    func    b    table: 0x8fbc80
    func    c    function: 0x8fbcc0
    func    d    true
    func    e    string

    HOOK    a    table: 0x8f77b0
    HOOK    b    function: 0x8f7590
    HOOK    c    3
    HOOK    d    c
    HOOK    e    c

(same as 5.2)

LuaJIT seems to manage:

    func    a    10
    func    b    table: 0x40622d08
    func    c    function: 0x4061f780
    func    d    true
    func    e    string

    HOOK    a    10
    HOOK    b    table: 0x40622d08
    HOOK    c    function: 0x4061f780
    HOOK    d    true
    HOOK    e    string

Test script attached.

I checked the attached script and examined the source code of Lua.
interestingly, if you return something (even `nil') instead of nothing from that function,
you'll get the expected result (I have Lua 5.2 installed, but I believe it applies to 5.3):

  func    a       10
  func    b       table: 000000000052BB20
  func    c       function: 000000000052CDE0
  func    d       true
  func    e       string

  HOOK    a       10
  HOOK    b       table: 000000000052BB20
  HOOK    c       function: 000000000052CDE0
  HOOK    d       true
  HOOK    e       string

for me, it feels like a bug (or call it a glitch) of Lua in this special situation.
I'll explain it in detail.

Lua calls the debug hook in function `luaD_poscall' (ldo.c), which is called by the VM
when executing the OP_RETURN instruction (lvm.c). but the OP_RETURN instruction will first
adjust the stack, according to the returning values.
this is all good, except when the function returns NOTHING, in which case the RA register
of OP_RETURN is 0, so the VM simply empty the the (still semantically active) stack frame.
thus you actually get values probably located in the stack frame of the hook itself
when you call debug.getlocal.

when the function returns NOTHING (either an explicit `return' statement or implicitly),
Lua generate this opcode:

  RETURN 0 1

when the function returns some value (e.g. nil), Lua generate this opcode:

  RETURN 8 2

in the latter case, the VM still adjust the stack before calling the return hook, but since
the returnning values are loaded at the top of the stack, the active stack frame holding the
local variables is not destroyed, so your hook can now get the expected results.

For now I'll probably try to use the line hook, discarding the results of all calls except the last for each function.

see the workaround I mentioned above.


the nerdy Peng / 书呆彭 / Sent from Thunderbird