让手机微信闪退 浏览器崩溃 电脑内存飙升甚至卡死的代码分析

0x00起因

坑主在群里发的一段代码,一段神奇的字符串,接收到的大部分安卓机微信崩溃,iOS机器会卡顿很长一段时间,至今不明原因……(谁知道原理给我讲一下,红包感谢)
代码及触发效果如下:

于是我想起来之前看到的一段javascript代码,转发到朋友或微信群后点击能使微信崩溃,浏览器打开后会崩溃甚至白苹果,电脑打开可使内存飙升甚至占满虚拟内存(硬盘空间),导致电脑完全卡死!今天我分析一下这段javascript的代码。内容简单,大神勿喷。(可怜)

0x01代码分析

在正式说崩溃原因之前让我分析下这段javascript代码,其实这才是我最想知道的部分,毕竟我是程序猿。(苦笑)
代码仅有寥寥几行:

var total="";
for (var i=0;i<1000000;i++)
{
    total= total+i.toString();
    history.pushState(0,0,total);
}

一行一行讲一下…… 额,真的没啥可讲的,太简单了,可以看到仅仅一个循环,里面最主要的函数就是history.pushState(),那么就研究它到底是个神马东西吧。

10年前网站和现在的网站的区别

写过前端的程序猿一定使用过“history.go(-1)”、“history.back()”等操作让浏览器后退一页,相当于帮用户点击浏览器左上角的后退。这是HTML4时代的history API。我们倒退10年回忆下那个时代网站的特点(感觉我暴露年龄了……(叹气))
10年前的网站大多是一个个的页面组成的,点一个超链接跳转到下一个页面,点一个按钮跳转到下一个页面,诸如此类,每个页面展示单一的信息。用户若要连续填写一系列表单可能是这样:

用户点击超链接->
浏览器跳转到“http://www.xxxx.com/step1”->
用户填写完成第一步信息,点击下一步->
浏览器跳转到“http://www.xxxx.com/step2”->
用户填写完成第二步信息,点击下一步->
浏览器跳转到“http://www.xxxx.com/step3”->
……->
用户填写完第n步信息点击保存->
浏览器跳转到“http://www.xxxx.com/finish”

而现在页面的复杂程度已经是当年不可想象的,程序猿们利用ajax技术,可以无刷新的实现页面跳转,在一个页面中可以搞定整个业务逻辑,用户在这期间并不会感受到页面的刷新,也不用等待浏览器读条,用户体验大大改善。用户若要连续填写一系列表单可能是这样:

用户点击超链接->
浏览器跳转到“http://www.xxxx.com/Forms”->
用户填写完成第一步信息,点击下一步->
浏览器ajax请求第二步信息,浏览器url依旧为“http://www.xxxx.com/Forms”->
用户填写完成第二步信息,点击下一步->
浏览器ajax请求第三步信息,浏览器url依旧为“http://www.xxxx.com/Forms”->
……->
用户填写完第n步信息点击保存->
浏览器跳转到“http://www.xxxx.com/finish”

从上面假设场景对比可以看出,10年前的网站每一步操作完成后会请求下一个页面,浏览器url随之改变,用户点击浏览器上的后退按钮可以回退到上一步操作,而现在的网站每一步操作均是ajax无刷新请求,url不变,用户若是点击浏览器的后退按钮很可能导致之前填写的内容全部丢失,从头再来。一些用户也会因此抱怨投诉。

HTML5的新增API

到了HTML5时代,HTML5终于给history对象增加了几个函数去解决上面的问题

  • history.pushState(data, title [, url]):往历史记录堆栈顶部添加一条记录;data会在onpopstate事件触发时作为参数传递过去;title为页面标题,当前所有浏览器都会 忽略此参数;url为页面地址,可选,缺省为当前页地址;
  • history.replaceState(data, title [, url]) :更改当前的历史记录,参数同上;
  • history.state:用于存储以上方法的data数据,不同浏览器的读写权限不一样;
  • window.onpopstate:响应pushState或replaceState的调用;

有了这几个新的API,针对支持的浏览器,我们可以构建用户体验更好的应用。比如上面提到的表单,我们既可以使用ajax实现无刷新的请求,又可以改变浏览器的url让用户可以后退。github,网络相册都在采用这样的技术。

Ajax 配合 pushState 例子

现在我们可以用Ajax + pushState来提供全新的ajax调用风格。以jQuery为例,为了SEO需要,应该为a标签的onclick添加方法。

$("~target a").click(function(evt){
    evt.preventDefault(); // 阻止默认的跳转操作
    var uri=$(this).attr('href');
    var newTitle=ajax_Load(uri); // 你自定义的Ajax加载函数,例如它会返回newTitle
    document.title=newTitle; // 分配新的页面标题
    if(history.pushState){
        var state=({
        url: uri, title: newTitle
        });
        window.history.pushState(state, newTitle, uri);
    }
    else{ window.location.href="#!"+~fakeURI; } // 如果不支持,使用旧的解决方案
    return false;
});
function ajax_Load(uri){ ... return newTitle; } // 你自定义的ajax函数,例如它会返回newTitle

这样在点击相应链接时可以无刷新的加载新内容,浏览器url也会随之改变。

pushState 配合 popstate 监听

想要良好的支持浏览器的历史前进后退操作,应当部署popstate监听:

window.addEventListener('popstate', function(evt){
    var state = evt.state;
    var newTitle = ajax_Load(state.url); //你自定义的ajax加载函数,例如它会返回newTitle
    document.title=newTitle;
}, false);

据说现在有人对这部分又做了一层封装叫pjax,这货我也没用过,用到的时候看一下。

0x02崩溃原因

再看下那段崩溃代码:

var total="";
for (var i=0;i<1000000;i++)
{
    total= total+i.toString();
    history.pushState(0,0,total);
}

崩溃原因分析其实我并不擅长,我也欠缺一些对javascript的深入理解,就用网上大神们的分析吧

  • pushState将指定的URL添加到浏览器历史里,存储当前历史记录点。 当 i<100000 的时候会循环的将 total记录到浏览器历史里面,重复多了,浏览器就承受不住了,自然就崩了。
  • the problem isn't history limit, it doesn't actually go above 50. The underlying issue is that the IPC queue doesn't have a limit, so we have a TON of IPCs queued up because of the pushState call in a loop. It just takes lots of CPU and time to process through the messages.
    拙劣翻译:
    问题不在history的限制,因为他根本没有超过50,根本原因是IPC消息队列没有限制,因为pushState调用了一个循环所以我们得到了大量的IPC消息队列,它们很消耗CPU资源和时间。

0x03如何去玩

这段代码可以用来吓唬你的小伙伴啦!找个服务器或者空间,写个html文件部署上这段代码,发给小伙伴。如果有支持微信分享的博客还可以这样玩:


效果就是这样:


当然也可以发挥自己的想象力想出各种玩法。
我作死在安卓、iOS和电脑上都试了一下,安卓浏览器闪退,iOS如果在微信打开微信会闪退,如果在Safari打开会白苹果重启,至于电脑……

涂掉是因为我露脸了……此时我已经无法对电脑进行任何操作……
虚拟机又跑了一遍并把url复制下来是这样的:

0x04参考资料

[1]知乎:网上流行的12行代码为什么会让浏览器崩溃?
[2]HTML5 history新特性pushState、replaceState
[3]不刷新改变URL: pushState + Ajax
[4]Hang bug in history.pushState()

Comments
Write a Comment
  • 小粉丝x5 reply

    何故os会奔溃,说明上版本的时候,开发小哥哥内心是奔溃的。。。

    • 图南 reply

      不不不 这代码无解的 电脑也会崩溃的。。。算是html5的一个bug吧。。。@小粉丝x5