请选择 进入手机版 | 继续访问电脑版
Mozilla

火狐社区

登录    注册

用新浪微博连接 QQ互联

WebAssembly的内存以及它的安全机制

yingliu Mozilla员工 发表于 2017-8-24 15:44:27 | 显示全部楼层 [复制链接]
1 5373
本帖最后由 yingliu 于 2017-8-24 15:54 编辑

WebAssembly 处理内存(memory)的方式和 JavaScript 不太一样。WebAssembly 能让你直接存取内存内的原始位……而造成有些人担心不够安全。不过,WebAssembly 的做法其实比你想象得更安全。

什么是内存对象?
当 WebAssembly 模块被实体化(instantiate)后,它会需要内存对象。你可建立和发送一个全新的 WebAssembly.Memory 物件。如果你不想这么做的话,WebAssembly 还可自动产生一个内存对象,并将之附加于实体(instance)上。

所有的 JavaScript 引擎内部都会产生 ArrayBuffer(作者在另一篇文章中已介绍过)。ArrayBuffer 是 JS 所参照的 JavaScript 物件。JS 会帮你配置内存。你只需告诉它要用多少内存,它就会建立符合该容量的 ArrayBuffer (数组缓冲区)。

02-01-500x384.png

你可以把数组(array)的索引(indexes)看成是内存的地址。如果你之后需要更多内存,你还能让数组「长大」(此作法称为 growing)。

通过把 WebAssembly 的内存当作 ArrayBuffer 来处理(也就是当成一个JavaScript 对象),你可达成两个目的:
  • 更轻松地在 JS 与 WebAssembly 之间传递 values
  • 加强内存管理的安全性

在 JS 与 WebAssembly 之间传递值
因为 WebAssembly 的内存只是个 JavaScript 对象,所以,JavaScript 也可使用到此内存位。如此一来,WebAssembly 和 JavaScript 便可共享内存,并且来回传送值。

它们会使用数组索引来存取数组内的每一格,而不是使用内存地址。
例如,若 WebAssembly 要在内存中放入一个字符串。它会把字符串转成位编码……

02-02-500x370.png

……然后,再把那些位放入数组。

02-03-500x371.png

之后,WebAssembly 会回传第一个整数 (integer) 索引给 JavaScript,以便 JavaScript 选取那些位来使用。

02-04-500x365.png

由于 JavaScript 大多不知道如何直接使用位,所以你还需要帮 JavaScript 加点工,就像你帮 WebAssembly 做的一样,才能把位转换成更有用的值(如字符串)。

在一些浏览器上,你可使用 TextDecoderTextEncoder APIs。或者你也可在 .js 文件内加入补助函数。如果要增加编码和译码的补助函数,你可以使用 Emscripten 这一类的工具。

02-05-500x387.png

这就是 WebAssembly 内存身为 JS 对象的第一个好处——让 WebAssembly 与 JavaScript 直接经由内存彼此传送值。

把内存存取变得更安全
WebAssembly 内存只是 JS 对象的另一个好处是:安全。它能避免浏览器层级的内存泄漏,并能达成内存隔离,使得实际操作更安全。

内存泄漏(Memory leaks)
我在内存管理的文章中曾提过,如果自己管理内存的话,常常容易因为忘记清理内存,而造成系统内存不足的状况。

如果 WebAssembly 模块可直接存取内存,万一它也忘记在内存用光前腾出空间的话,就会造成浏览器泄漏内存。

不过,由于内存对象只是个JavaScript 对象,对象本身会受到垃圾回收器 (Garbage Collector)的监控(但其内容不会)。

也就是说,当 WebAssembly 实体所附带的内存对象耗尽内存时,垃圾回收器 (Garbage Collector)会把整个内存数组都清理干净。

02-06-500x369.png

内存隔离(Memory isolation)
很多人一听到 WebAssembly 可以直接存取内存时,都会变得有点紧张。因为他们担心万一出现恶意的 WebAssembly 模块,它就能长驱直入,接触到不该触碰的内存。不过,那是不可能的。

ArrayBuffer 的外围构成隔离的边界,会限制住 WebAssembly 模块所能直接接触到的内存区块。

02-07-500x374.png

尽管 WebAssembly 模块能直接接触数组内的位,却无法看到在数组范围以外的任何东西。

譬如,WebAssembly 便无法存取内存内的其他 JavaScript 对象(如 window global)。这一点对保障安全来说极为重要。

每当 WebAssembly 要加载程序或存储对象时,WebAssembly 引擎便会检查数组的范围,以确保该地址位于相对应的WebAssembly 实例的内存中。

若有程序代码试图存取数组范围以外的地址,WebAssembly 引擎则会发出通知,进而保障其他内存的安全。

02-08-500x371.png

以上是 memory import 的介绍。你还可以阅读另一篇文章,进一步了解另外一种有助于加强安全性的 import——table import


作者:Lin Clark,Mozilla 开发工程师


310971373 狐狸精
发表于 2017-8-25 09:11:03 | 显示全部楼层
沙发沙发,简单易懂的教程,支持哦!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发新帖
论坛更多 »
火狐微信
快速回复 返回顶部 返回列表