检测 Lua 脚本中的死循环

本贴最后更新于 2687 天前,其中的信息可能已经天翻地覆

论坛上有人问,所以把以前做的东西拿出来秀一下。

Lua 是一门小巧精致的语言,特别适用于嵌入其它的程序为它们提供脚本支持。不过脚本通常是用户编写的,很有可能出现死循环,虽说这是用户的问题,但却会造成我们的宿主程序死掉。所以检测用户脚本中的死循环并中止这段脚本的运行就显得非常重要了。

可是,一个现实的问题是死循环并不好检测,一些隐藏较深的死循环连人都很难找出来,更不用说让机器去找了。所以实际采用的方案多是检测脚本的执行时间,如果超过一定的限度,就认为里面有死循环,我下面的例子也是用的这种方法。

以下是几个相关的全局变量(我是喜欢把 C++ 当 C 用的程序员,C++ 的忠实粉丝请忍耐一下😄)的定义。

lua_State* g_lua = NULL; // lua脚本引擎 volatile unsigned g_begin = 0; // 脚本开始执行的时间 volatile long g_counter = 0; // 脚本执行计数, 用于判断执行超时 volatile long g_check = 0; // 进行超时检查时的执行计数

run_user_script 用来执行用户脚本,它首先通过 GetTickCount 把当前的时间记录到 g_begin 中去。然后将 g_counter 加一,在执行完用户脚本后再将其加一,这样就可以保证执行用户脚本时它是个奇数,而不执行时是偶数,检测脚本超时的代码可以籍此来判断当前是否在执行用户脚本。还要注意调用用户脚本要使用 lua_pcall 而不是 lua_call,因为我们中止脚本的执行会产生一个 Lua 中的“错误”,在 C/C++ 中它是一个异常,只有用 lua_pcall 才能保证这个错误被 Lua 脚本引擎正确处理。

int run_user_script( int nargs, int nresults, int errfunc ) { g_begin = GetTickCount(); _InterlockedIncrement( &g_counter ); int err = lua_pcall( g_lua, nargs, nresults, errfunc ); _InterlockedIncrement( &g_counter ); return err; }

下面的 check_script_timeout 用来检测脚本超时,需要在另外一个线程中周期性的调用,原因我想就不用解释了吧。它首先检查是否在执行用户脚本,或者是否已经让当前执行的用户脚本中止过。然后看这段脚本执行了多长时间,超过限度就把当前脚本计数记录到 g_check 中去,并通过 lua_sethook 设置一个钩子函数 timeout_break,这个钩子函数会在用户脚本执行时被调用。

void check_script_timeout() { long counter = g_counter; // 没有执行用户脚本, 不检查超时 if( (counter & 0x00000001) == 0 ) return; // 已经让当前执行的用户脚本中止了 if( g_check == counter ) return; // 如果执行时间超过了设置的超时时间(这里是1秒), 终止它 if( GetTickCount() - g_begin > 1000 ) { g_check = counter; int mask = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; lua_sethook( g_lua, timeout_break, mask, 1); } }

最后就是那个钩子函数了,它首先把钩子去掉,因为这个钩子只要执行一次就行了。由于设置钩子和执行钩子是在不同的线程中,并且钩子从设置到执行需要一定的时间,所以它要通过对比 g_checkg_counter 来判断是否还在运行判断超时所执行的那段脚本,不是就什么也不做,是就通过 luaL_error 产生一个错误,并中止脚本的执行,而这个错误最终会被 run_user_script 中的 lua_pcall 捕获。

void timeout_break( lua_State* L, lua_Debug* ar ) { lua_sethook( L, NULL, 0, 0 ); // 钩子从设置到执行, 需要一段时间, 所以要检测是否仍在执行那个超时的脚本 if( g_check == g_counter ) luaL_error( L, "script timeout." ); }

上面的检测使用了两个线程,其实在一个线程中也可以做到,并且更简单。但那样会导致钩子函数频繁执行,影响效率,如果对性能没什么要求的话,也可以采用。

  • Lua
    17 引用 • 17 回帖 • 1 关注
  • 算法
    425 引用 • 254 回帖 • 24 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • lpy
    该回帖仅作者和楼主可见

推荐标签 标签

  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 2 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 27 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 12 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 447 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖 • 2 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖 • 2 关注
  • OnlyOffice
    4 引用 • 19 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    53 引用 • 190 回帖
  • RemNote
    2 引用 • 16 回帖 • 26 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 630 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 674 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖 • 2 关注
  • sts
    2 引用 • 2 回帖 • 247 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 368 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 1 关注
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1251 回帖 • 390 关注
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    108 引用 • 295 回帖 • 2 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 146 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    43 引用 • 44 回帖
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 648 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 641 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 357 关注