虽然,除此之外,也存在 Go 挪用 Lua 模块,但小我私人感受后者是没啥须要的,以是在这里并没有涉及后者的内容。
- package main
- import (
- "fmt"
- lua "github.com/yuin/gopher-lua"
- )
- const source = `
- local m = require("gomodule")
- m.goFunc()
- print(m.name)
- `
- func main() {
- L := lua.NewState()
- defer L.Close()
- L.PreloadModule("gomodule", load)
- if err := L.DoString(source); err != nil {
- panic(err)
- }
- }
- func load(L *lua.LState) int {
- mod := L.SetFuncs(L.NewTable(), exports)
- L.SetField(mod, "name", lua.LString("gomodule"))
- L.Push(mod)
- return 1
- }
- var exports = map[string]lua.LGFunction{
- "goFunc": goFunc,
- }
- func goFunc(L *lua.LState) int {
- fmt.Println("golang")
- return 0
- }
- // golang
- // gomodule
变量污染
当我们行使实例池镌汰开销时,会引入另一个棘手的题目:因为统一个假造机也许会被多次执行同样的 Lua 代码,进而变换了个中的全局变量。假如代码逻辑依靠于全局变量,那么也许会呈现难以猜测的运行功效(这有点数据库断绝性中的“不行一再读”的味道)。
全局变量
假如我们必要限定 Lua 代码只能行使局部变量,那么站在这个起点上,我们必要对全局变量做出限定。那题目来了,该怎样实现呢?
我们知道,Lua 是编译成字节码,再被表明执行的。那么,我们可以在编译字节码的阶段中,对全局变量的行使作出限定。在查阅完 Lua 假造机指令后,发明涉及到全局变量的指令有两条:GETGLOBAL(Opcode 5)和 SETGLOBAL(Opcode 7)。
到这里,已经有了大抵的思绪:我们可通过判定字节码是否含有 GETGLOBAL 和 SETGLOBAL 进而限定代码的全局变量的行使。至于字节码的获取,可通过挪用 CompileString(...) 和 CompileFile(...) ,获得 Lua 代码的 FunctionProto ,而个中的 Code 属性即为字节码 slice,,范例为 []uint32 。
在假造机实当代码中,我们可以找到一个按照字节码输出对应 OpCode 的器材函数。
- // 获取对应指令的 OpCode
- func opGetOpCode(inst uint32) int {
- return int(inst >> 26)
- }
有了这个器材函数,我们即可实现对全局变量的搜查。
- package main
- // ...
- func CheckGlobal(proto *lua.FunctionProto) error {
- for _, code := range proto.Code {
- switch opGetOpCode(code) {
- case lua.OP_GETGLOBAL:
- return errors.New("not allow to access global")
- case lua.OP_SETGLOBAL:
- return errors.New("not allow to set global")
- }
- }
- // 对嵌套函数举办全局变量的搜查
- for _, nestedProto := range proto.FunctionPrototypes {
- if err := CheckGlobal(nestedProto); err != nil {
- return err
- }
- }
- return nil
- }
- func TestCheckGetGlobal(t *testing.T) {
- l := lua.NewState()
- proto, _ := CompileString(`print(_G)`)
- if err := CheckGlobal(proto); err == nil {
- t.Fail()
- }
- l.Close()
- }
- func TestCheckSetGlobal(t *testing.T) {
- l := lua.NewState()
- proto, _ := CompileString(`_G = {}`)
- if err := CheckGlobal(proto); err == nil {
- t.Fail()
- }
- l.Close()
- }
模块
除变量也许被污染外,导入的 Go 模块也有也许在运行时代被改动。因此,我们必要一种机制,确保导入到假造机的模块不被改动,即导入的工具是只读的。 (编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|