Flash毒药收集

第一剂:

new Matrix3D().append(null);

杀伤力: 4星
辐射面: flash cs4, flashplayer 10.*, as3
症状: flash cs4 意外退出,flashplayer 10.*直接crash
来源: D.S

第二剂:

var a=<a><n/></a>
a.@* = a.@*;
a.toString();

杀伤力: 5星
辐射面: flash cs3/4, flashplayer 9/10, as3
症状: flash cs3, 4 crash,flashplayer9以上播放swf时直接crash
来源: Ticore's Blog

第三剂:

Object['isPrototypeOf']();
Object['hasOwnPrototype']();
Object['propertyIsEnumerable']();
Object['setPropertyIsEnumerable']();

//(以上任意一行)

杀伤力: 5星
辐射面: flash cs3/4, flashplayer 9/10, as3
症状: flash cs3, 4 crash,flashplayer9以上播放swf时直接crash
来源: Ticore's Blog

AS3处理GB2312数据的严重BUG

BUG描述:

flash as3使用URLLoader & URLRequest加载gb2312文本时,字符串内存边界判断有误,导致读出的数据结尾有随机乱码或者数据读取不完整。

捉虫全记录:

> 使用as3加载解析XML时,发现偶尔会抛出XML格式错误的异常,运气不好的话出现频率非常之高;

> 用trace显示数据内容时,发现文件有时加载不全、有时尾部有随机乱码;

> 使用抓包软件发现数据完全正常,所以肯定是flash搞的鬼;

> 开始怀疑文本编码导致的问题,将文件存为utf-8后,完全没问题;

> 试了多次,随机内容有时完全是无关的东东,偶尔还有其它进程里的一些数据;

> 到此为止,可以肯定是内存字符串结束符处理问题;

影响面:

flashplayer 9, 10

解决方案:

方案一: 尽量不要使用gb2312数据源,如果非用不可,可参考《方案二》;

方案二: 建立socket连接,自已发送http header,接收数据进行解析,如果遇到跨域问题则看《方案三》;

方案三: 在数据尾部加入特殊的结束符(比如:),数据加载完成后把结束符后的内容全部去掉,如果遇到加载不完整的情况,则重试加载(记得要限制次数),不能100%保证,经过测试重试后成功率99.9%;

附件:

BUG演示程序

 

根据allen的处理方法,进一步追查了原因,可以确切的定位出是ByteArray.toString方法的BUG所致:

> URLLoader.data 是 ByteArray 类型,所以只要把 e.target.data as String 改为 e.target.data.readMultiByte(e.target.data.length, "gb2312") 即可以解决问题;

> e.target.data as String 实际上是执行了 ByteArray 的 toString 方法,那么很可能BUG是出在 ByteArray.toString 方法;

> ByteArray相当于是向量数组,length值应该是根据写入数据长度来改变,所以length值无论如何都是正确的,所以按上面 readMultiByte 方法读取,不会读出多余的数据,而 ByteArray.toString 方法并不能使用属性length来获取数据长度,需要根据编码类型来动态计算,正常来说是不会有错的,错就错在处理部分编码类型时使用了strlen或sizeof去获取数据长度,而ByteArray是可以存任何二进制数据的,当然不会有\0结束,这样的情形下strlen和sizeof是绝对不可信赖的;

> 只有这样才能解释 toString 的BUG。
 
结论是:
不要尝试使用 ByteArray.toString 的方法来获取 gb 编码的数据,最好是根据目标编码,使用 readMultiByte 读取。

有用的formatString,支持Actionscript1.0

有用过C#, C/C++, PHP的人都应该知道string.Format或者printf吧! 下面我们让AS也有这样的功能. 什么? 没听说过 ... 拖出去TJJ ...

 
var formatString = function(m)
{
  if (m.indexOf("{")==-1) return m;
  var r="",n="";
  for(var i=0;i<m.length;i++)
  {
    if (m.charAt(i)=="{")
    {
      i++;
      for(n="";m.charAt(i)!="}";i++)
        n+=m.charAt(i);
      if (isNaN(parseInt(n)))
      {
        r+="{";
        i-=n.length+1;
        continue;
      }
      i++;
      r+=arguments[parseInt(n)+1];
    }
    r += m.charAt(i);
  }
  return r;
};
 
/* usage:
var model = "<font size='{2}'><b>{0}</b>+<b>{1}</b>=<b>{0}</b></font>";
var str = formatString(model, 100, 0, 9);
trace(str);
// output: <font size='9'><b>100</b>+<b>0</b>=<b>100</b></font>
*/ 就这么简单, 如果觉得不爽, 你可以继续使用:
var str = "<font size='"+9+"'><b>"+100+"</b>+<b>"+0+"</b>=<b>"+100+"</b></font>";
trace(... 狂呕中 ...
 

顺便说一句: 函数体不用修改, 直接拿到html里当Javascript使, 也可以

瘦版的Delegate,支持Actionscript1.0

 Actionscript 2.0 内置了mx.utils.Delegate的类, 用法就不说了, 自己查查Google, 写了个瘦版的, 经测试可以支持Actionscript 1.0 ...

 
var fns = [];
var delegate = function(o, f)
{
    var i = fns.length;
    var fn = function(){ fns[i].f.apply(fns[i].o, [arguments,this]); };
    fns[i] = {o:o, f:f};
    return fn;
}
 
/* usage:
var onStart = function()
{
    trace(this);
};
 
btn_start.onRelease = delegate(this, onStart); // output: _level0
//btn_start.onRelease = onStart; // output: _level0.btn_start
*/
 

为什么说是廋版的呢, 其实就是编译后的文件小了一些, 看数据:

使用 mx.utils.Delegate, 文件大小会增加841 byte, 使用上面的代码, 文件大小只增加379 byte, 瘦了462 byte, 相当于小了一半多, 如果算上调用语法所占的大小, 应该不只少462 byte.虽然按字节数来说, 瘦得不多, 可是大家都知道积少成多的道理, 环保呀 ...