[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

Yiniau發表於2019-03-03

title: WebAssembly中的記憶體(為什麼它比你想象的更安全)

date: 2018-3-22 23:58:00

categories: 翻譯

tags: WebAssembly

source: 原文地址

auther: Lin Clark


WebAssembly中的記憶體(為什麼它比你想象的更安全)


這是此係列的第二篇文章:


WebAssembly中的記憶體與JavaScript中的記憶體稍有不同。使用WebAssembly,您可以直接訪問原始位元組…並且會讓一些人感到擔憂。但它實際上比你想象的更安全。

什麼是memory物件?

當一個WebAssembly模組被例項化時,它需要一個記憶體物件。你可以建立一個新的WebAssembly.Memory物件並將該物件傳入。如果不存在,則會建立一個記憶體物件並將其自動附加到該例項。

所有JS引擎在內部都會建立一個ArrayBuffer(我在另一篇文章中解釋過)。ArrayBuffer是一個物件,JS對其保持引用。JS為你分配記憶體。你告訴它需要多少記憶體,它會建立一個給定大小的ArrayBuffer。

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

陣列的索引可以看作是記憶體地址。如果需要更多的記憶體,你可以做一些叫做 growing(增長) 的事情來擴大陣列。

將WebAssembly的記憶體作為JavaScript中的一個物件 – 作為ArrayBuffer處理 – 做到了兩件事:

  1. 便於JS和WebAssembly之間的傳值
  2. 使記憶體管理更加安全

在JS和WebAssembly之間傳遞值

因為這只是一個JavaScript物件,這意味著JavaScript也可以挖掘出這些記憶體中的位元組。於此,WebAssembly和JavaScript可以通過共享記憶體並來回傳遞值。

他們不使用記憶體地址,而是使用陣列索引來訪問每個box(記憶體單元)。

例如,WebAssembly可以在記憶體中放置一個字串。它會將它編碼成位元組……

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

…然後將這些位元組放入陣列中。

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

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

現在,大多數JavaScript方法不知道如何直接使用位元組。因此,你需要JavaScript端的一些東西,就你您在WebAssembly端做的那樣,它可以將位元組轉換為更有用的值,比如字串。

在某些瀏覽器中,你可以使用TextDecoder和TextEncoder API。或者你可以在你的.js檔案中新增輔助函式。例如,像Emscripten這樣的工具可以新增編碼和解碼輔助。

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

這就是使用JS物件作為WebAssembly記憶體的第一個好處。WebAssembly和JavaScript可以通過記憶體直接傳遞值。

記憶體洩漏 Memory leaks

正如我在關於記憶體管理的文章中提到的那樣,當你手動管理記憶體時,你可能會忘記清除它。這可能會導致系統記憶體不足。

如果WebAssembly模組例項可以直接訪問記憶體,並且在記憶體離開作用域之前忘記清除記憶體,則瀏覽器可能會發生記憶體洩露。

但是因為記憶體物件只是一個JavaScript物件,所以它本身被垃圾收集器跟蹤(即使它的內容不是)。

這意味著,當記憶體物件所附的WebAssembly例項離開作用域時,整個記憶體陣列可能會被垃圾收集。

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

記憶體隔離 Memory isolation

當人們聽到WebAssembly能讓你直接訪問記憶體時,它可能會讓一些人有點緊張。他們認為一個惡意的WebAssembly模組可以進入記憶體並且在記憶體中進行挖掘,但它不應該這樣做。但事實並非如此。

ArrayBuffer的陣列範圍天然提供了一個邊界。這是WebAssembly模組可以直接觸控記憶體的限制。

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

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

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

當在WebAssembly中載入或儲存時,引擎會執行陣列邊界檢查(array bounds checks)以確保地址位於WebAssembly例項的記憶體中。

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

[譯] WebAssembly中的記憶體(為什麼它比你想象的更安全)

這就是記憶體匯入。在下一篇文章中,我們將看看另一種匯入更安全的匯入方法…table import(匯入表格)

相關文章