加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

当Go赶上了Lua,会产生什么

发布时间:2019-03-15 08:23:20 所属栏目:建站 来源:Jiahonzheng
导读:在 GitHub 玩耍时,偶尔发明白 gopher-lua ,这是一个纯 Golang 实现的 Lua 假造机。我们知道 Golang 是静态说话,而 Lua 是动态说话,Golang 的机能和服从各说话中示意得很是不错,但在动态手段上,必定是无法与 Lua 对比。那么假如我们可以或许将二者团结起

虽然,除此之外,也存在 Go 挪用 Lua 模块,但小我私人感受后者是没啥须要的,以是在这里并没有涉及后者的内容。

  1. package main  
  2. import (  
  3.     "fmt"  
  4.     lua "github.com/yuin/gopher-lua"  
  5. )  
  6. const source = `  
  7. local m = require("gomodule")  
  8. m.goFunc()  
  9. print(m.name)  
  10. func main() {  
  11.     L := lua.NewState()  
  12.     defer L.Close()  
  13.     L.PreloadModule("gomodule", load)  
  14.     if err := L.DoString(source); err != nil {  
  15.         panic(err)  
  16.     }  
  17. }  
  18. func load(L *lua.LState) int {  
  19.     mod := L.SetFuncs(L.NewTable(), exports)  
  20.     L.SetField(mod, "name", lua.LString("gomodule"))  
  21.     L.Push(mod)  
  22.     return 1  
  23. }  
  24. var exports = map[string]lua.LGFunction{  
  25.     "goFunc": goFunc,  
  26. }  
  27. func goFunc(L *lua.LState) int {  
  28.     fmt.Println("golang")  
  29.     return 0  
  30. }  
  31. // golang  
  32. // gomodule 

变量污染

当我们行使实例池镌汰开销时,会引入另一个棘手的题目:因为统一个假造机也许会被多次执行同样的 Lua 代码,进而变换了个中的全局变量。假如代码逻辑依靠于全局变量,那么也许会呈现难以猜测的运行功效(这有点数据库断绝性中的“不行一再读”的味道)。

全局变量

假如我们必要限定 Lua 代码只能行使局部变量,那么站在这个起点上,我们必要对全局变量做出限定。那题目来了,该怎样实现呢?

我们知道,Lua 是编译成字节码,再被表明执行的。那么,我们可以在编译字节码的阶段中,对全局变量的行使作出限定。在查阅完 Lua 假造机指令后,发明涉及到全局变量的指令有两条:GETGLOBAL(Opcode 5)和 SETGLOBAL(Opcode 7)。

到这里,已经有了大抵的思绪:我们可通过判定字节码是否含有 GETGLOBAL 和 SETGLOBAL 进而限定代码的全局变量的行使。至于字节码的获取,可通过挪用 CompileString(...) 和 CompileFile(...) ,获得 Lua 代码的 FunctionProto ,而个中的 Code 属性即为字节码 slice,,范例为 []uint32 。

在假造机实当代码中,我们可以找到一个按照字节码输出对应 OpCode 的器材函数。

  1. // 获取对应指令的 OpCode  
  2. func opGetOpCode(inst uint32) int {  
  3.     return int(inst >> 26)  

有了这个器材函数,我们即可实现对全局变量的搜查。

  1. package main  
  2. // ...  
  3. func CheckGlobal(proto *lua.FunctionProto) error {  
  4.     for _, code := range proto.Code {  
  5.         switch opGetOpCode(code) {  
  6.         case lua.OP_GETGLOBAL:  
  7.             return errors.New("not allow to access global")  
  8.         case lua.OP_SETGLOBAL:  
  9.             return errors.New("not allow to set global")  
  10.         }  
  11.     }  
  12.     // 对嵌套函数举办全局变量的搜查  
  13.     for _, nestedProto := range proto.FunctionPrototypes {  
  14.         if err := CheckGlobal(nestedProto); err != nil {  
  15.             return err  
  16.         }  
  17.     }  
  18.     return nil  
  19. }  
  20. func TestCheckGetGlobal(t *testing.T) {  
  21.     l := lua.NewState()  
  22.     proto, _ := CompileString(`print(_G)`)  
  23.     if err := CheckGlobal(proto); err == nil {  
  24.         t.Fail()  
  25.     }  
  26.     l.Close()  
  27. }  
  28. func TestCheckSetGlobal(t *testing.T) {  
  29.     l := lua.NewState()  
  30.     proto, _ := CompileString(`_G = {}`)  
  31.     if err := CheckGlobal(proto); err == nil {  
  32.         t.Fail()  
  33.     }  
  34.     l.Close()  

模块

除变量也许被污染外,导入的 Go 模块也有也许在运行时代被改动。因此,我们必要一种机制,确保导入到假造机的模块不被改动,即导入的工具是只读的。

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读