RFC-0033:處理未知欄位和嚴格程度 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 這個 FTP 修訂並釐清 FIDL 解碼器在遇到資料表、可延伸的聯集、列舉和位元 (可延伸訊息) 時的行為,其中包含類型不明的欄位。 |
作者 | |
提交日期 (年-月-日) | 2019-02-07 |
審查日期 (年-月-日) | 2019-03-07 |
摘要
此 FTP 修訂並闡明 FIDL 解碼器在 遇到資料表、可延伸的聯集、列舉和位元... 可延伸訊息[^1]:包含 類型未知。
具體來說,我們建議:
- 針對可延伸訊息定義嚴格且有彈性的行為。 指定解碼器如何遇到不明欄位 (包括控制代碼) 行為;
- 在可延伸訊息前面加上
strict
關鍵字 宣告。 這可以保證會收到沒有未知欄位的訊息。 在驗證期間 拒絕這些要求 - 預設可延伸訊息具有彈性,例如 允許透過繫結公開且值不明的值。
- 定義並推薦繫結提供給用戶端的 API 檢查有不明欄位的訊息。
與其他 RFC 的關係
此 RFC 已修訂者:
提振精神
可延伸訊息是實現資料互換的重要機制 格式,在不破壞線格式 (二進位) 相容性的情況下發展。 然而,變更結構定義會導致 FIDL 解碼器的設計決定 因為您需要驗證、剖析及公開這些欄位 而非使用者
每種語言的資料結構各有不同的機制和規範 指定解碼器及其 API 的行為,提升安全性 藉由強制執行驗證行為,並改善整體的人體工學 提高各種類型和語言的一致性
我們也希望為受限環境啟用繫結,其中 要正確作業及添加錯誤,可能需要剖析不明欄位。 不利於效能負擔 這也適用於已成熟的郵件,且 不會進一步發展
設計
不明欄位是指此欄位的序數 (表格)、標記 (可延伸聯集), 讀取器無法辨識值 (列舉) 或特定位元 (位元)。 接著,我們會使用「tag」代表「未知」的 為求簡潔,序數/標記/值/特定位元。
- 含有不明標記的訊息「必須」經過驗證及剖析
- 不過,請參閱下文 嚴格訊息。
- 解碼器「必須」處理訊息中的不明控點。
- 系統預設的處理行為「必須」關閉所有帳號代碼。
- 繫結 MAY 可提供用戶端處理不明機制 採取特殊處理方式
- 繫結「必須」提供用來偵測不明標記的機制 才會包含在訊息中
- 繫結「必須」提供偵測欄位是否含有 收到的訊息中會有指定的標記。
- 繫結 MAY 可提供讀取標記、原始資料和及 (未類型) 控制代碼。
指定語言是否提供完整檢查代碼的機制 編譯期間 (例如 C/C++ 中的
switch()
、Rust 中的match
):- 該語言繫結應提供「未知」的加上標記
可納入詳細檢查,如此一來
(例如:C/C++ 中的
default
、Rust 中的_
) 可以省略。 - 這項建議的目的是避免全部接收 並不需要適當地編譯 。
- 這個 FTP 未定義方式 。因為不同語言的導入策略不同。
範例:
// Bindings SHOULD NOT offer this API: switch(union.Which()) { case Tag1: ... case Tag2: ... case Tag3: ... default: ... // no unknown tag in bindings forces handling using default case } // Bindings SHOULD offer this API: switch(union.Which()) { case Tag1: ... case Tag2: ... case Tag3: ... case Tag_Unknown: ... // no default case: new tags cause a non-exhaustiveness warning }
- 該語言繫結應提供「未知」的加上標記
可納入詳細檢查,如此一來
(例如:C/C++ 中的
嚴格處理訊息
- 我們推出了
strict
關鍵字,可加上可延伸訊息前置字元 聲明,例如strict table T { ... }
或strict enum T { ... }
。 - 含有不明欄位的嚴格訊息「必須」視為無效。
- 繫結「不得」提供特殊「未知」完整代碼 檢查嚴格訊息 (如果支援這類彈性訊息機制) 訊息。
- 從嚴格訊息轉換為彈性訊息,反之亦然
必須受到支援,可能是非破壞性來源層級 (API) 變更,可能
使用
[Transitional]
屬性進行柔和轉換。- 這類轉場效果「不得」變更線路格式 (ABI)。
嚴格郵件無法遞移性。 如果郵件標示為「嚴格」,則只會對郵件套用嚴格規則。 郵件內含的子訊息並不嚴格。
語法範例:
// One simply doesn't walk into Mordor and add a new file mode, so this is // reasonable to be strict. strict bits UnixFilePermission : uint16 { ... }; // It's too dangerous for clients to ignore data in this table if we // extend it later, but we wish to keep the wire format compatible if we // do change it, so it's not a struct. strict table SecurityPolicy { ... };
執行策略
- 更新 FIDL 相容性測試,驗證現有語言
繫結必須符合這項規格
- 針對含有 (1) 已知欄位的訊息新增測試案例,(2) ,以及 (3) 至少一個已知和一個未知欄位。
- 確保 FIDL 相容性測試含有測試空白訊息的測試案例 所有適當類型
- 支援在
fidlc
中新增嚴格訊息。 - 更新語言繫結,支援嚴格的訊息。
- 將嚴格訊息的測試案例新增至 FIDL 相容性測試。
未來計畫:使用網站修飾符
在設計階段,我們也考慮允許嚴格關鍵字 除了提議的宣告內容外 宣告網站刊登位置
範例語法可以是:
protocol Important {
SomeMethod(...) -> (strict other.library.Message response);
}
此處的 other.library.Message
可能尚未定義 strict
,
我們想要全部使用
同時需要嚴格驗證
這會增加繫結作者的設計複雜度,
嚴格模式和彈性模式可能需使用 other.library.Message
模式。
在編碼/驗證/解碼時,公開嚴格和彈性 相同訊息的模式與上下文有何差別 也能處理字串或向量 兩者的版面配置相同,但邊界會因實際情況而有所不同 以及他們最常使用的位置 這也類似於可延伸聯集在可為空值或 不可為空值的結構定義 一般來說,繫結會選擇類型結構定義,並藉由某種方式表示 邊界、是否可為空值 或者目前所介紹的嚴格模式
第二個問題是,要針對相同格式 同時推出嚴格模式和彈性模式 是處理訊息組合和查詢 使用者程式碼中的訊息
舉例來說,假設某個列舉有三個成員,分別是 A
、B
和 C
。
為了公開彈性模式,我們需要特殊列舉成員
「未知」。
因此,現在可以組合不會傳遞的列舉
嚴格驗證,在列舉
但若使用嚴謹的情境,編碼期間將會失敗。
這裡說,在處理字串和向量的情況下,平行處理速度很重要:如果沒有
相當專業的 API,繫結可讓您建立字串和向量
長度過長,因而無法編碼。
同時支援嚴格和彈性調整時應遵循的策略 都是針對彈性模式產生所有額外部分 編碼、解碼 和驗證。
人體工學
此 FTP 透過以下幾個方面提升人體工學:
- 我們最好設定使用者對各種語言 FIDL 行為的期望
- 嚴格訊息可讓使用者避免編寫不必要的程式碼, 處理未知的欄位
說明文件和範例
- 文法與語言規格更新時,必須採用嚴格格式 只要使用來自這些領域的 小型資料集訓練即可
- 請務必更新 FIDL 樣式指南,以便瞭解何時 宣告嚴格訊息模式
回溯相容性
- 這項變更不會影響 ABI 相容性。
- 如需變更解碼器或繫結以符合這個 FTP 這些變更可能會導致來源層級 (API) 故障, 我們會依照個案情形處理。
成效
- 強制解碼器和繫結以符合此 FTP 時, (可能不明顯) 導致效能降低 並關閉所有控點
- 繫結可能需要額外的間接層級 (因此會使用 額外記憶體/二進位檔大小),以提供「未知」鉅細靡遺的標記 廣告代碼檢查
安全性
這個 FTP 會提升安全性。
- 我們會針對含有不明內容的郵件指定驗證行為。
- 嚴格訊息可讓解碼器驗證並捨棄不明訊息 進而降低錯誤發生的可能性
測試
請參閱「導入策略」一節 (我們 執行 FIDL 相容性測試)。 此外,每個語言繫結都應有自己的測試 系統的行為正確
缺點、替代方案和未知
此 FTP 大致說明行為,並且具有相關實作方式 確保語言繫結符合建議項目。
替代模式:預設為嚴格模式或混合模式
嚴格來說,在與向量大小範圍相近的燈光下檢視 或字串;是獨立於訊息版面配置之外的 而且可在沒有 ABI 中斷的情況下變更。
我們希望 FIDL 作者能夠明確選擇限制 (限制) 他們的訊息。
此外,我們不希望混用模式,包括部分訊息 (例如列舉) 預設為嚴格限制,其他 (例如資料表) 則不。
替代關鍵字:[Strict] 屬性,而非新關鍵字
您應該要擁有自己專屬的關鍵字。 為其他語言中的類似功能具備足夠先例 正確轉譯為 FIDL
替代關鍵字:其他關鍵字
在設計階段,我們提出了幾種不同的替代方案。
最可能的競爭者是 final
:表示「
主題」在 C++、Java、C# (和其他項目) 中的優先順序。
反之,為了使用「final」這個關鍵字通訊協定上 表示不得用於組合 (也就是 「最終」代表,我們選擇採用另一個關鍵字搭配嚴格驗證。
這樣就打開大門,引進下列語法:
final strict protocol Important {
MyMethod(SomeTable arg);
};
這表示通訊協定 Important
無法組合;且
所有驗證都必須嚴格
其他研究的關鍵字為:sealed
、rigid
、fixed
、closed
、
known
,以及 standardized
。
替代做法:僅限嚴格
可延伸訊息一律設為嚴格模式, 目前列舉和位元都嚴格,所以這個替代做法 會擴充至資料表和可延伸的聯集
在這樣的情境下,變更可延伸結構 (例如新增 新欄位) 要求讀者在「先」更新 已更新。 這會嚴重限制使用這些可擴充資料結構的功能, 對高階用途而言過於限制。
此外,如果這是設計選項,我們就不需要使用 餐桌和可延伸工會的信封 (也就是說,不需要有 或帳號代碼的數量)。 的確,在嚴格解釋的情況下,不明欄位會是 否則結構定義會判定位元組數 和其他訊息一樣的使用方式 FIDL 程序。
替代做法:僅限彈性
我們可以定義所有可延伸訊息,使其保持靈活。
以列舉 (和位元) 來說,這個做法非常令人驚訝 期望。 這會導致我們有兩個不良的替代文案:
- 為列舉 (和位元) 設有例外狀況,以便嚴格遵守, 這會造成混淆,使語言規則更難 好瞭解。
- 讓這些訊息保持靈活,不過這反而會抵銷 培養好奇心和修正錯誤 (例如讀取無效的值) 也一定會導致許多基本驗證碼 或由繫結提供。
繼續探索其他可延伸訊息 (資料表和 可延伸的工會),則有一段空間,並務必嚴格限制。
舉例來說,假設定義了安全記錄通訊協定 LogEntry
並排成表格。
導入這項通訊協定可能會確保
用戶端不會傳送伺服器無法辨識的欄位;擔心
這些客戶可能會預期這些新欄位可能的控制方式
處理記錄項目。
舉例來說,較新的版本可能會新增「pii ranges
」欄位提供
包含 PII 且必須特別記錄的記錄項目範圍
(例如以專屬 ID 取代,其中原始資料會保存在
專屬 ID)。
防止舊伺服器接受這類酬載,且可能未妥善處理
這些記錄項目
作者就會選擇嚴格模式
LogEntry
,從而保護自己免於潛在濫用的威脅。
既有藝術品和參考資料
我們根據 go/proto3-unknown-fields - 說明為何 proto3 不支援保留不明欄位,然後 後來撤銷了原決定
- FTP-037:交易郵件標頭 v3 (尚未發布)
Footnote1
列舉和延伸訊息中會包含位元,因為新成員可能會 定義。