lua-users home
lua-l archive

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



2015-03-27 21:16 GMT-07:00 Sean Conner <sean@conman.org>:
  I have the following code:

        local a = 3

        function foo(x)
          local y = 4 * x + a
          print(y)
          return y
        end

        f = io.open("blob","wb")
        x = string.dump(foo)
        f:write(x)
        f:close()

        info = debug.getinfo(foo,"u")
        for i = 1 , info.nups do
          name,value = debug.getupvalue(foo,i)
          print(i,name,value)
        end

  I run it.  I now have a file of binary sludge that represents the
function foo(), and the output is:

        1       a       3
        2       _ENV    table: 0x9af23c0

  Okay.  No guarentee that the first upvalue is _ENV.  That shouldn't be a
problem, right?  Anyway, here's the second script I have.

        f = io.open("blob","rb")
        d = f:read("*a")
        f:close()

        bar = load(d)

        info = debug.getinfo(bar,"u")
        for i = 1 , info.nups do
          name,value = debug.getupvalue(bar,i)
          print(i,name,value)
        end

  And when I run it, I get:

        1       a       table: 0x9b4b3c0
        2       _ENV    nil

  Um ... to me, this looks like a bug.  The *names* are in the right order,
but the *values* appear to have been swapped.  Or rather, load() just jammed
_ENV as the first upvalue, original order be damned!  The documentation for
string.dump() says:

        Returns a string containing a binary representation (a binary chunk)
        of the given function, so that a later load on this string returns a
        copy of the function (but with new upvalues). If strip is a true
        value, the binary representation is created without debug
        information about the function (local variable names, lines, etc.).

        Functions with upvalues have only their number of upvalues saved. When
        (re)loaded, those upvalues receive fresh instances containing nil. (You can
        use the debug library to serialize and reload the upvalues of a function in
        a way adequate to your needs.)

  Well, first off, this is wrong---all but the first upvalue are nil.  And if
you receive stripped code, you don't even get the names!  [1]  Okay, so it
seems I have to shuffle things around.

        _,v = debug.getupvalue(bar,1)
        debug.setupvalue(bar,1,3)
        debug.setupvalue(bar,2,v)
        bar(3)

  And now it works.

  Also, while "you can use the debug library to serialize and reload the
upvalues of a function in a way adequate to your needs" is true, to a
degree, as mentioned elsewhere [2] it's not always that easy.

  -spc (Why yes, I'm trying to serialize Lua functions, silly me)

[1]     In playing around with this, it seems that sometimes _ENV is the
        first upvalue, sometimes the last.  Fun times.

[2]     http://lua-users.org/lists/lua-l/2015-03/msg00180.html


 
I have three points regarding this:

First, this isn't 5.3 specific. You'd get the same in 5.2.

Second, the document load() says it sets the "first" upval. Well, that's correct from the perspective of implementation. However, its intention is really to set the ONLY upval. The implied recommendation is, don't play load() with anything but main chunk (which does not have upval except _ENV).

Third, well, the document says you can serialize Lua function by string.dump and deserialize it by load. That's fine. Only in this case, you deserialize what you serialize, and you should not make any assumption what the "first" would be.