[譯]安全的WebAssembly記憶體操作

xlaoyu發表於2018-03-31

作者:Lin Clark
譯者:xlaoyu
英文原文:Memory in WebAssembly (and why it’s safer than you think)

轉載請註明出處,保留原文連結以及作者資訊


這是 WebAssembly 使用系列介紹的第二篇文章:

  1. 使用JavaScript建立WebAssembly模組例項
  2. 安全的WebAssembly記憶體操作
  3. WebAssembly的匯入型別 table 到底是什麼?

Memory(記憶體,記憶體都以記憶體稱呼)在 WebAssembly 中的使用和在 JavaScript 中稍有不同。在 WebAssembly 裡,我們可以直接訪問原始位元組,這可能會讓一些人感到擔憂,但它實際上比你想象的更安全。

什麼是記憶體物件?

當一個WebAssembly模組被例項化時,它需要一個記憶體物件。我們可以建立一個新 WebAssembly.Memory 物件並將其傳入。或者如果我們沒傳,那麼引擎將建立一個記憶體物件並自動將其附加到該例項上。

所有 JS 引擎都會在內部建立一個ArrayBuffer。ArrayBuffer 是 JS 引用的 JavaScript 物件,JS 替我們為它分配記憶體。我們告訴它需要多少記憶體,它會建立我們需要大小的 ArrayBuffer 物件。

arraybuffer

陣列的索引可以看作是記憶體地址。如果以後我們需要更多的記憶體空間,可以執行一種叫做 增長 的操作來擴大陣列。

使用 JavaScript 的物件 ArrayBuffer 來操控 WebAssembly 的記憶體,達成了兩個目的:

  1. 使在 JS 和 WebAssembly 之間互相傳遞資料更簡單
  2. 有助於記憶體管理的安全性

在 JS 和 WebAssembly 之間傳遞資料

因為 ArrayBuffer 也只是一個 JavaScript 物件,這意味著 JavaScript 有足夠的能力可以去操作記憶體裡的位元組。基於這種方式,WebAssembly 和 JavaScript 可以共享記憶體並來回傳遞值。

它們使用陣列下標去定位記憶體塊,而不是使用記憶體地址。

例如,WebAssembly 可以把一個字串放進記憶體裡。首先把字串編碼為位元組。。

encode

然後把位元組放進陣列中。

put-array

然後它會將第一個索引(整數)返回給 JavaScript,所以 JavaScript 可以將位元組取出來並使用它們。

return-index

目前為止,大多數 JavaScript 引擎都無法直接使用位元組來工作,所以我們需要在 JS 這邊使用某些方法把位元組轉化為有用的資料型別,比如字串。

在某些瀏覽器中,我們可以使用 TextDecoderTextEncoder API。或者我們可以像 Emscripten 那樣在程式碼中加入輔助函式,幫助我們完成這件事情。

use-bytes

以上是使用 JS 物件操作 WebAssembly 記憶體的第一個優點:可以直接通過記憶體互相傳遞資料

讓記憶體訪問更安全

使用 JavaScript 物件處理 WebAssembly 記憶體的另外一個好處就是:安全性。通過幫助防止瀏覽器級記憶體洩漏並提供記憶體隔離,它使事情更安全。

記憶體洩漏

當我們自己手動管理記憶體時,隨時可能忘記清除它。這可能會導致系統記憶體不足最終記憶體溢位。

我們想象一下,如果一個 WebAssembly 模組例項可以直接訪問記憶體,並且在該例項執行完成退出上下文時忘記釋放該記憶體,那麼將會導致記憶體洩露。但是現在由於記憶體物件是一個 JavaScript 物件,它的存在將由垃圾回收器追蹤著(儘管並沒有控制內容)。這意味著當 WebAssembly 模組例項離開執行上下文時,整個記憶體陣列將會被回收掉。

gc

記憶體隔離

當人們得知 WebAssembly 模組可以直接訪問記憶體時,這可能會讓我們有點緊張。我們可能會以為 WebAssembly 模組可以定位和訪問到它們本該不能訪問的記憶體,但事實並非如此。

ArrayBuffer 物件邊界會提供一個限制,這是 WebAssembly 模組能直接接觸到的記憶體邊界。

boundary

WebAssembly 可以直接獲取該陣列內部的位元組,但它不能看到超出此陣列邊界的任何內容。

例如,記憶體中的任何其他JS物件(如全域性window)都不能被 WebAssembly 訪問。這對安全性非常重要。

無論何時在 WebAssembly 中進行讀取或寫操作時,引擎都會執行陣列邊界檢查以確保地址位於 WebAssembly 例項的記憶體中。

如果程式碼嘗試訪問超出界限的地址,則引擎將引發異常,這保護了其餘的記憶體。

[譯]安全的WebAssembly記憶體操作


下篇文章,我們一起來看看什麼是 WebAssembly 的 table 物件。

相關文章