Ozzypig
|
  |
| Joined: 27 Mar 2008 |
| Total Posts: 4906 |
|
|
| 31 Mar 2012 07:21 PM |
| Write a function that, when given a function, will return a boolean value that represents whether or not the given function has upvalues. |
|
|
| Report Abuse |
|
|
KingBoo
|
  |
| Joined: 16 Jul 2007 |
| Total Posts: 8495 |
|
|
| 31 Mar 2012 07:40 PM |
function x() return false end
lololol |
|
|
| Report Abuse |
|
|
| |
|
MrNicNac
|
  |
| Joined: 29 Aug 2008 |
| Total Posts: 26567 |
|
|
| 31 Mar 2012 07:54 PM |
I have no way of testing the following, and it's clearly skeptical.
function hasUpvalues(xFunction) return #getfenv(xFunction)>0 end |
|
|
| Report Abuse |
|
|
oysi92
|
  |
| Joined: 20 Nov 2008 |
| Total Posts: 361 |
|
|
| 31 Mar 2012 08:01 PM |
@MrNicNac Upvalues are local variables and parameters. And getfenv only gives a table containing the global variables of the script. So, that wouldn't work.
@Ozzypig I'm 100% certain you have to use string.dump to do this. If only I knew Lua Assembly... |
|
|
| Report Abuse |
|
|
nate890
|
  |
| Joined: 22 Nov 2008 |
| Total Posts: 21686 |
|
|
| 31 Mar 2012 08:32 PM |
| Only way to do this is knowing LASM, as oysi stated in his last post. Once you decode what string.dump returns, you would then parse the source looking for the "local" keyword. |
|
|
| Report Abuse |
|
|
Anaminus
|
  |
 |
| Joined: 29 Nov 2006 |
| Total Posts: 5945 |
|
|
| 31 Mar 2012 08:41 PM |
I believe the location of the number of upvalues for a dumped function in the dumped string would be the following:
12 + 4 + name + 4 + 4
Where `name` is the length of the source name. You can get that from bytes 13 to 16 in the dumped string (which represents a 4-byte integer). I'm going to cheat a bit and just use byte 13 because the source name generally doesn't go over 255 characters anyway.
function GetNumUpvalues(func) local source = string.dump(func) local name = string.byte(source:sub(13)) local up = 12 + 4 + name + 4 + 4 return string.byte(source:sub(up,up)) end
Also, I have no idea if this is right. |
|
|
| Report Abuse |
|
|
| |
|
|
| 31 Mar 2012 09:47 PM |
@Anaminus: Yours does not work.
local a, b, c, d, e, f, g; local func = function() print(a, b, c, d, e, f, g); end; print(GetNumUpvalues(func)); --> 0
For several reasons: 1.) The name field is Null terminated when it's length is > 0, otherwise nothing follow. Note: unlike string constants, the Null terminator is not included in the integer size of the string.
2.) You missed an integer most likely somewhere (not sure which) because the upvalue offset is 4 (excluding previous null terminator thing) bytes further along
3.) I've seen roblox embed the entire source of a script into the name field of a bytecode dump. Reading the full dword integer isn't hard.
Also, you missed the part of the OP where it said "return a boolean value that represents whether or not the given function has upvalues." Though I encorporated your idea of just returning the number of upvalues instead as well.
Here's a working implementation:
function has_upvalues(func) local dump = ("").dump(func); -- pretty nice, eh? local bytes = {dump:byte(13, 16)}; -- get integer size of the name string local name_len = bytes[1] + bytes[2]*0xFF + bytes[3]*0xFFFF + bytes[4]*0xFFFFFF; -- decode the integer local upvalue_position = 28 + (name_len > 0 and 1 or 0) + name_len; local number_upvalues = dump:byte(upvalue_position); -- return the number of upvalues return number_upvalues > 0, number_upvalues; end
Usage/Proof:
local a, b, c; local func1 = function() print(); end; local func2 = function() print(a, b); end; local func3 = function() print(a, b, c); end; print(has_upvalues(func1)); --> false, 0 print(has_upvalues(func2)); --> true, 2 print(has_upvalues(func3)); --> true, 3 |
|
|
| Report Abuse |
|
|
miloguy
|
  |
| Joined: 19 Dec 2009 |
| Total Posts: 7702 |
|
|
| 31 Mar 2012 10:14 PM |
function n(f) for i,v in pairs(f) do return true end return false end
I'm not exactly sure what upvalues are. Looking that up now |
|
|
| Report Abuse |
|
|
miloguy
|
  |
| Joined: 19 Dec 2009 |
| Total Posts: 7702 |
|
|
| 31 Mar 2012 10:17 PM |
Oh.
Yeah, I had the wrong idea entirely ._. |
|
|
| Report Abuse |
|
|
nate890
|
  |
| Joined: 22 Nov 2008 |
| Total Posts: 21686 |
|
|
| 01 Apr 2012 12:08 AM |
| Miloguy, upvalues are local variables. |
|
|
| Report Abuse |
|
|
Ozzypig
|
  |
| Joined: 27 Mar 2008 |
| Total Posts: 4906 |
|
|
| 01 Apr 2012 12:25 AM |
| Oh okay then. Bonus points for returning the exact number of upvalues. |
|
|
| Report Abuse |
|
|
Anaminus
|
  |
 |
| Joined: 29 Nov 2006 |
| Total Posts: 5945 |
|
|
| 01 Apr 2012 02:08 AM |
"2.) You missed an integer most likely somewhere (not sure which) because the upvalue offset is 4 (excluding previous null terminator thing) bytes further along"
That doesn't seem to be right. I was only off by 1 because I didn't compensate for the null byte (seems the source I learned from was wrong). I didn't miss any integers, so the offset should be 24, not 28. |
|
|
| Report Abuse |
|
|
|
| 01 Apr 2012 09:24 AM |
@Anaminus:
Huh, does my example work on your computer? Lua bytecode is terribly platform dependent. |
|
|
| Report Abuse |
|
|
Anaminus
|
  |
 |
| Joined: 29 Nov 2006 |
| Total Posts: 5945 |
|
|
| 01 Apr 2012 01:11 PM |
No, it doesn't. Maybe it's because we've been assuming that the header info has been the same. Here's your function modified to check the size of ints and string size. It gives the right results for me. Does it work for you?
function has_upvalues(func) local dump = ("").dump(func); -- pretty nice, eh? local int_len,size_t_len = dump:byte(8,9) local bytes = {dump:byte(13, 12+size_t_len)}; -- get integer size of the name string local name_len = bytes[1] for i=2,#bytes do -- decode the integer name_len = name_len + bytes[i]*(256^(i-1)-1) end local upvalue_position = 12 + size_t_len + (name_len > 0 and 1 or 0) + name_len + int_len + int_len; local number_upvalues = dump:byte(upvalue_position); -- return the number of upvalues return number_upvalues > 0, number_upvalues; end |
|
|
| Report Abuse |
|
|
|
| 02 Apr 2012 04:55 PM |
Yeah that works.
Curse you Lua and your inability to produce cross platform bytecode!
|
|
|
| Report Abuse |
|
|