作者:Lin Clark
譯者:xlaoyu
英文原文:WebAssembly table imports… what are they?
轉載請註明出處,保留原文連結以及作者資訊
這是 WebAssembly 使用系列介紹的第二篇文章:
- 使用JavaScript建立WebAssembly模組例項
- 安全的WebAssembly記憶體操作
- WebAssembly 的 table 物件是什麼
在第一篇文章中已經介紹過可以匯入 WebAssembly 模組例項中四種不同型別的值了:
- values
- function imports
- memory
- tables
前三種我們都見過用過或者在之前的文章介紹了,但是對於最後一個可能大家都會疑惑:它到底是什麼和有什麼作用?
在 JS 中,我們都知道函式表示式能賦值給一個變數,換一種說法即是變數指向了函式。然後我們可以使用這個變數(函式表示式)做一些事情,比如將它傳遞給另外一個函式作為回撥函式:
在 C 語言中這個變數被稱為函式指標(function pointers)。函式儲存在記憶體中,而這個變數(函式指標)僅僅儲存的是指向該函式的記憶體地址(memory address)。
這個指標變數能根據我們的需要在不同時間指向不同的函式(也就是不同的記憶體地址),如果學過 C 或者 C++ 對這個概念應該不陌生。
在網頁中,我們都知道所有函式實際也是一個 JavaScript 物件,並且由於這個特性,所以它們所使用的記憶體地址在 WebAssembly 的記憶體區域外。
如果我們想在 WebAssembly 中擁有一個指向該函式的變數,那麼我們需要獲取到該函式的地址並且放入 WebAssembly 記憶體中。
但是保證網頁安全的其中一點就是需要保持記憶體地址的不可見性,我們不希望頁面中的程式碼能夠檢視並且修改那些記憶體地址。想象一下,如果頁面中存在惡意程式碼並且能修改記憶體,那麼它們將可以利用記憶體相關知識去製造漏斗。
舉個?,它可以去把某個指向函式地址的變數改為指向另外一個函式的地址(一個惡意函式),那麼當使用者嘗試去呼叫該變數(函式)時,就觸發了攻擊者的指定的任何內容了。
惡意程式碼可能會以任何方式插入到頁面中,也許就在某個字串裡。這時候我們需要一種機制來實現安全的函式指標 — table。
WebAssembly 的 table 型別能使我們在避免遭受各種攻擊的方式下使用函式指標特性。
table
是一個位於 WebAssembly 記憶體之外的陣列,它的值就是對函式的引用。
在底層,引用就是記憶體地址。但由於它不在 WebAssembly 的記憶體中,因此 WebAssembly 無法看到這些地址,但是它可以訪問到陣列索引。
當 WebAssembly 模組想要去呼叫這些函式的時候,可以使用陣列索引通過所謂的 間接呼叫(call_indirect)
Table.prototype.get 去呼叫函式。
Ps:一下是譯者引用 MDN 上的一段程式碼和註釋
var tbl = new WebAssembly.Table({initial:2, element:"anyfunc"});
console.log(tbl.length); // "2"
console.log(tbl.get(0)); // "null"
console.log(tbl.get(1)); // "null"
var importObj = {
js: {
tbl:tbl
}
};
// 假設 table2.wasm 包含兩個函式(一個返回42,另一個返回43)然後把兩個函式儲存在 table 的 0 和 1 索引位置中
WebAssembly.instantiateStreaming(fetch(`table2.wasm`), importObject)
.then(function(obj) {
console.log(tbl.length);
console.log(tbl.get(0)()); // 42
console.log(tbl.get(1)()); // 43
});
複製程式碼
element – A string representing the type of value to be stored in the table. At the moment this can only have a value of “anyfunc” (functions).
initial – The initial number of elements of the WebAssembly Table.
現在,表格的用例非常有限。它們被新增到規範中以支援這些函式指標,因為 C 和 C++ 非常依賴這些函式指標。
正因為如此,目前我們可以放入表中的唯一引用是對函式的引用。但是隨著WebAssembly功能的擴充套件(例如,當新增對DOM的直接訪問時),我們能看到 table 上儲存更多型別的引用以及執行除了間接引用外其他的操作。