Няма лесен отговор (все още след всички тези години). Ще опиша по-подробно алтернативите.
1 отговор на проф. по археология (и малко разглобяване):
Отговорът на този древен въпрос се крие в първичния. А именно luadec. Вероятно тогава е бил в режим на престой, но поне към момента има актуализирана версия, който обработва lua 5.1-.3.
Освен това string.dump
предоставя не пълен безсмислен текст, той дава програмен код в необработени байтове от машинни инструкции, можете да видите по-добро представяне на тези с luac -l -p <filename>
. Vm кодовете не са документирани добре, но хората са сглобили нещо тук. Luajit има малко по-добра документация за собствен набор от инструкции.
Възстановяването на кода от vm инструкциите е това, което прави luadec. На теория можете също така да свържете вашите собствени инструкции направо в изхвърлен низ.
Въпреки това, какъвто и трик да направите с байт кодовете, той ще изпита несъвместимост между различни интерпретатори, включително различни версии на самата lua.
2. Всъщност правя X
Преобразуването на функция в низ е доста странно желание (освен ако не правите генериране на код, в който случай вече имате низа на първо място).
„Кодът за регистриране и инжектиране“ наистина е доста общ X, което може да наложи решаването на Y. Но единични случаи могат да бъдат обхванати от единични мерки. Lua е много гъвкав език и например можете да проследите потока на стойността x
в примера, като я направите обект:
local to2number = tonumber
tonumber= function(o)
local r= to2number(o)
if not r then
local m= getmetatable(o)
if m and m.__tonumber then
r=m.__tonumber(o)
end
end
return r
end
local number
number={
new=function(n)
return setmetatable({n},number)
end,
__add=function(me,other)
print("I'm "..tostring(me).." and I'm being added to "..tostring(other))
local o=tonumber(other)
return number.new(me[1]+o)
end,
__tonumber=function(me) return me[1] end,
__tostring=function(me) return tostring(me[1]) end,
}
test(number.new(4), number.new(10))
Както в примера по-горе, можете да инжектирате поведение, като промените средата на функцията. А именно, там предефинирах глобалната функция tonumber
. Може да искате да опаковате напълно функцията в различна среда:
local test = function() print"hello" end
local newenv={print=function(s) print(s..'world') end}
setfenv(test,newenv)--this is lua 5.1, luajit, good luck with upvalues
local test = load(string.dump(test),nil,nil,newenv)--this is lua 5.2-5.3, good luck with upvalues
test()
За по-стари версии ще трябва да обработвате upvalues, които може да имат препратки към глобални функции, които се опитвате да предефинирате. За по-новите версии ще трябва да се справите с upvalues, които биха били загубени по време на процеса на дъмп-зареждане.
3. Четене на файловете
И накрая, както казаха други, ако имате достъп до източника, можете да опитате да намерите дефиницията на функцията от него. Освен ако не е дефиниция на една функция или един файл за връщане, задачата може да се окаже еквивалентна на повторно внедряване на lua анализатора. Има повече от един от тях, но те не са направени с подобна функционалност в ума, така че може да отнеме малко работа, за да пренастроите техния код.
Ако всички функции са дефинирани сами и сте готови да се ограничите малко, можете да използвате отново lua metatables, решете проблема по време на етапа на кодиране:
local def=function(code,env)
env=env or _ENV
local compiled,q=load("return "..code,nil,nil,env)
if not compiled then error(q) end
local f=compiled()
return setmetatable({code=code},{__call=function(me,...) return f(...) end})
end
local test=def[[function(a,b)
return a+b
end]]
print(test(2,3))
Определянето на upvalues обаче ще бъде трудно.
person
Dimitry
schedule
16.05.2017