如何检测JavaScript中的死循环示例详解


Posted in Javascript onAugust 30, 2020

前言

如果我们需要执行用户写的代码,如和避免死循环?我们最近遇到了这个问题,因为写错代码很常见,所以我们进行了一下尝试。

如何检测JavaScript中的死循环示例详解

首先我们需要使用iframe

这主要是安全考虑,我们需要一个sandbox环境来执行JavaScript,避免影响到整体。iframe的sandbox属性可以用来禁止弹窗等等,非常有用。

地址可以选择Blob url,不过blob url会持有当前web page的origin,如果用户拷贝一些乱七八糟的代码不小心执行的话,会有安全问题。所以最终决定用data URI。

iframe的执行仍然在同一个thread

iframe中执行了代码,发生死循环的时候,浏览器还是死掉了,因为iframe和parent还是在同一个thread。也就是说,我们无法在parent中进行timeout检测,因为检测代码在死循环发生时永远不会被执行。

Web Worker可行但不支持DOM API

如果是纯粹的JavaScript代码,或许用web worker可以,但是我们需要DOM API,所以Web Worker也不在考虑范围之中。

看来只能修改用户代码了

假设大多数死循环都是由while/for引起的,如果我们能插入一些代码并在每一次循环中进行检测,我们也许就可以根据某些条件提前终止循环。

比如这样的代码

function abc() {
 while (true) {
  console.log(Date.now())
 }
}

如果我们插入一个 __detectInfiniteLoop() 方法,并在while loop里面调用的话,就可以在loop 10000次的时候报错终止执行。

let __count = 0
const __detectInfiniteLoop = () => {
 if (__count > 10000) {
  throw new Error('Infinite Loop detected')
 }
 __count += 1
}

function abc() {
 while (true) {
  console.log(Date.now())
  __detectInfiniteLoop()
 }
}

操作AST在合适位置插入代码

通过字符串匹配来编辑代码细节太复杂容易出错,我们可以用编辑AST的方式,实际上非常简单。

用到babel的3个package。

  1. @babel/parser - parse 代码为AST
  2. @babel/traverse - 搜索 for/while loop
  3. @babel/generator - 生成插入后的代码

首先 parse用户的代码为AST

import { parse } from '@babel/parser'
const ast = parse(code)

然后我们准备一下需要插入的代码。

代码有两部分,第一部分是function定义,实际上可以在头部插入,所以字符串就够了。第二部分是function的调用,这部分需要插入到AST中,所以也需要parse一下。

const prefix = `
 let __count = 0
 const __detectInfiniteLoop = () => {
  if (__count > 10000) {
   throw new Error('Infinite Loop detected')
  }
  __count += 1
 }
`

const detector = parse(`__detectInfiniteLoop()`)

接下来就找到 while/for/do..while 的位置,然后插入detector的调用。

import traverse from '@babel/traverse'
traverse(ast, {
 ForStatement: function (path) {
  path.node.body.body.push(...detector.program.body)
 },
 WhileStatement: function (path) {
  path.node.body.body.push(...detector.program.body)
 },
 DoWhileStatement: function (path) {
  path.node.body.body.push(...detector.program.body)
 }
})

AST修改好了,最后一步就是生成最终的代码,然后放到iframe中执行。

import generate from '@babel/generator'
const newCode = prefix + generate(ast).code

如何检测JavaScript中的死循环示例详解

如愿以偿!撒花!

最后

这个方法不是完美的,不过满足了我们自己的需求。你可以根据需要进行一下调整。

到此这篇关于如何检测JavaScript中的死循环的文章就介绍到这了,更多相关检测JavaScript死循环内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
syntaxhighlighter 使用方法
Jul 02 Javascript
javascript之更有效率的字符串替换
Aug 02 Javascript
时间戳转换为时间 年月日时间的JS函数
Aug 19 Javascript
JavaScript中的object转换成number或string规则介绍
Dec 31 Javascript
轻松掌握JavaScript享元模式
Aug 27 Javascript
vue.js树形组件之删除双击增加分支实例代码
Feb 28 Javascript
详解数组Array.sort()排序的方法
May 09 Javascript
JavaScript实现简单的四则运算计算器完整实例
Apr 28 Javascript
JavaScript之filter_动力节点Java学院整理
Jun 28 Javascript
用VueJS写一个Chrome浏览器插件的实现方法
Feb 27 Javascript
使用VUE实现在table中文字信息超过5个隐藏鼠标移到时弹窗显示全部
Sep 16 Javascript
在webstorm中配置less的方法详解
Sep 25 Javascript
JavaScript中CreateTextFile函数
Aug 30 #Javascript
详解vue组件之间的通信
Aug 30 #Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 #Javascript
JavaScript事件委托实现原理及优点进行
Aug 29 #Javascript
JS如何判断对象是否包含某个属性
Aug 29 #Javascript
JS获取当前时间戳方法解析
Aug 29 #Javascript
JS PHP字符串截取函数实现原理解析
Aug 29 #Javascript
You might like
DISCUZ 分页代码
2007/01/02 PHP
php Smarty 字符比较代码
2011/02/27 PHP
ThinkPHP3.1新特性之多层MVC的支持
2014/06/19 PHP
javascript学习随笔(使用window和frame)的技巧
2007/03/08 Javascript
jQuery之网页换肤实现代码
2011/04/30 Javascript
js中的如何定位固定层的位置
2014/06/15 Javascript
javaScript中两个等于号和三个等于号之间的区别介绍
2014/06/27 Javascript
jQuery实现form表单元素序列化为json对象的方法
2015/12/09 Javascript
jQuery与Ajax以及序列化
2016/02/01 Javascript
Bootstrap基本组件学习笔记之面板(14)
2016/12/08 Javascript
Canvas 制作动态进度加载水球详解及实例代码
2016/12/09 Javascript
js实现带简单弹性运动的导航条
2017/02/22 Javascript
xmlplus组件设计系列之下拉刷新(PullRefresh)(6)
2017/05/03 Javascript
js 客户端打印html 并且去掉页眉、页脚的实例
2017/11/03 Javascript
超轻量级的js时间库miment使用解析
2019/08/02 Javascript
vue+eslint+vscode配置教程
2019/08/09 Javascript
python模拟登陆Tom邮箱示例分享
2014/01/13 Python
Python 出现错误TypeError: ‘NoneType’ object is not iterable解决办法
2017/01/12 Python
python编程羊车门问题代码示例
2017/10/25 Python
Python爬虫_城市公交、地铁站点和线路数据采集实例
2018/01/10 Python
django启动uwsgi报错的解决方法
2018/04/08 Python
Python 数据可视化pyecharts的使用详解
2019/06/26 Python
为什么相对PHP黑python的更少
2020/06/21 Python
python如何快速拼接字符串
2020/10/28 Python
Python 将代码转换为可执行文件脱离python环境运行(步骤详解)
2021/01/25 Python
英国伦敦的睡衣品牌:Asceno
2019/10/06 全球购物
static函数与普通函数有什么区别
2015/12/25 面试题
如果NULL和0作为空指针常数是等价的,那我到底该用哪一个
2014/09/16 面试题
TCP协议通讯的过程和步骤是什么
2015/10/18 面试题
银行职员思想汇报
2013/12/31 职场文书
小学先进集体事迹材料
2014/05/31 职场文书
重大事项社会稳定风险评估方案
2014/06/15 职场文书
青年教师个人总结
2015/02/11 职场文书
党风廉洁教育心得体会
2016/01/20 职场文书
Python多线程 Queue 模块常见用法
2021/07/04 Python
Golang jwt身份认证
2022/04/20 Golang