RFC-0034:空值終止字串

RFC-0034:空值終止字串
狀態已遭拒
領域
  • FIDL
說明

我們提議讓 FIDL 中的字串視為空值 (但目前所有保留字串大小仍與目前的案例相同)。此外,變更 C 繫結,將字串資料使用 uint8_t*

作者
提交日期 (年-月-日)2019-02-08
審查日期 (年-月-日)2019-02-21

拒絕原因

摘要

我們建議:

  1. FIDL 中的字串將是空值 (保留 字串維持原樣;

  2. 變更 C 繫結,以使用 uint8_t* 處理字串資料。

提振精神

使用目前的 FIDL 字串編碼,很容易就會不小心以不安全的方式寫入 再也不是件繁重乏味的工作C 和低階 C++ 繫結用於某些特殊權限 程式碼,因此應針對 定義的政策

我們不慎遇到了 錯誤,但 Fuchsia 樹狀結構中程式碼的系統性稽核相當困難,而且無法防範 在樹狀結構中或第三方程式碼中重複。

設計

這建議將 FIDL 字串的編碼改為包含單一 值為零的結束字元位元組。這不會使 FIDL 字串與 C 字串,但是 FIDL 字串,系統會將其解讀為 C 字串 而不會超過預期時間,因此比較安全

線材格式

定義 線編碼字串如下 (變更會醒目顯示):

  • 代表文字的變數長度序列 UTF-8 編碼字元。
  • 可為空值;空值字串和空字串不同。
  • 可指定大小上限,例如string:40,最大 40 個位元組字串 (不包含空值結束字元)。
  • 字串內容具有空值結束字元。
  • 編碼器和解碼器「必須」驗證最後一個位元組後是否還有空值 字串的位元組,如長度所示。
  • 儲存為 16 位元組記錄,包含:
    • size:64 位元無正負號的程式碼單位數 (位元組),不含 空值結束字元
    • data:64 位元存在狀態指標或指標指向外部字串資料
  • 編碼用於轉移時,data 表示內容存在:
    • 0:字串為空值
    • UINTPTR_MAX:字串為非空值,資料是下一個外部物件
  • 如果經過解碼以便使用,data 會指向內容:
    • 0:字串為空值
    • <valid pointer>:字串不是空值,data 位於指定的記憶體中 地址

字串表示方式如下:

  • string:不可為空值的字串 (如果空值資料為 遇到)
  • string?:可為空值字串
  • string:Nstring:N?:長度上限為 N 個代碼單位的字串

這樣就會構成破壞線格式變更,具體來說是擁有 長度再除以 8 可增加 8 個位元組 (將對齊 8 個位元組, null 終止,導致另外 7 個位元組為了對齊 8 而加入為邊框間距 )。

編碼器需要更新,才能在編碼的字串中加入空值終止和 ,驗證字串內容中沒有任何空值字元。解碼器 必須更新,以檢查字串內沒有任何空值字元 但長度代表空值的結束字元。

C 繫結

目前 C 繫結將字串以 char*size_t 表示。如果這樣 char* 傳遞到函式中,該函式預期可能會解譯 C 字串 不正確。繫結將改為使用 uint8_t* 傳送字串資料指標到 strchr()printf("%s") 時, 下一步是使用 compile 方法 指定訓練方式,完成模型編譯

執行策略

這是一項破壞的線路格式變更。進行部署時 交叉使用 FIDL。

某些建構時間標記後面必須更新下列程式碼:

  • //zircon/system/ulib/fidl/walker.h (用於正確驗證字串)
  • //zircon/system/host/fidl/lib/flat_ast.cpp (更新 StringType::Shape)
  • //zircon/system/host/fidl/lib/c_generator.cpp (更新) EmitLinerarizeMessageProduceInterfaceClientImplementation 等)
  • //sdk/lib/fidl/hlcpp/string.cc
  • //garnet/public/lib/fidl/rust/fidl/src/encoding.rs
  • //third_party/go/src/syscall/zx/fidl/encoding.go (更新日期:marshalStringunmarshalString)
  • //third_party/go/src/syscall/zx/fidl/encoding_new.go (更新 mString)
  • //sdk/dart/fidl/lib/src/types.dart (更新 StringType)
  • llcpp 繫結
  • 其他語言的樹狀結構外繫結

請使用 fidl_compatibility_test 進行測試、執行測試 來確認預期的系統穩定性

確實反映變更需要與發布團隊協調 以及 Chromium 等外部團隊

人體工學

如此一來,C 和低階 C++ 繫結更容易正確使用,並能 也不會影響其他繫結

說明文件和範例

線路格式文件 (如上所述) 必須更新。

回溯相容性

這項變更與 API 相容,但是 ABI 不相容。

成效

這不會影響建構效能,但會產生下列小小規模 效能影響:

  • 每個字串平均需要花費 1 個位元組

安全性

這項異動旨在修正 使用 FIDL 防記憶體不安全的語言。

測試

系統會使用相容性測試套件進行測試。 延伸,確保處理 7、8 和 9 位元組長字串等極端情況 正確。

缺點、替代方案與不明

這會增加每個字串的平均 FIDL 訊息大小。 若是以 8 除盡的字串,長度維持不變。適用對象 長度除以 8 的字串,長度會增加 8 個位元組。

替代方案

什麼也不做

我們可以保留一切原樣,並仰賴程式碼審查和說明文件 確保使用者不會編寫錯誤的程式碼這個問題還稍微減緩 但會因採用新的低階 C++ 繫結而產生費用 由此微小問題引起的一系列錯誤 其次是可行的

空值終止,但禁止嵌入空值位元組 / 使用修改過的 UTF-8

(這是原始提案)

'\0' 是有效的 UTF-8 字元,且存在於 FIDL 使用者的 UTF-8 字串中 廣告空間類型限制空值的位元組會導致 FIDL 不適用於許多用途 修改後的 UTF-8 都會造成額外的負擔 UTF-8,可能含有空值位元組,已修改為 UTF-8。

只使用 uint8_t 取代 char

如果 FIDL 字串資料點是 uint8_t 而不是 char,就無法 必須在不轉換的情況下傳遞至標準字串函式或 printf。這會導致 協助揭露這類型的錯誤,但無法預防這類錯誤。

在偵錯版本中,填入有效的 ASCII 邊框間距

八個字串中的第 7 個後面會加上零填充位元組在偵錯中 我們可以將這些 0 變更為有效的 ASCII 字元 顯示列印或剖析的錯誤這些年秋 遠離塵囂

一律將字串移出行

C/C++ 繫結可以為字串和空值結束字元分配空間, 複製並終止接收的所有字串這會導致 C 和低階 C++ 繫結行為不可接受的效能成本。

將 ASan 建構作業的字串移出行

位址清理工具會檢查程式碼不會超過堆積分配量。適用對象 ASan 建構我們能針對堆積上的字串分配空間,並複製這些位元組 並將指標傳回呼叫端整合不易 若是 C 繫結,則可能隱含錯誤的行為 之間的關聯和發布子版本之間,而且無法避免開發人員在 Fuchsia 建構系統。

停止使用 C 和 C++

如果 Google 無法在 2019 年編寫安全的 C++,C++ 將不安全。很遺憾 C C++ 是許多裝置驅動程式庫作者和 供應商可選擇將現有的 C/C++ 驅動程式轉移至我們的平台。

不要向 C 公開原始字元

我們可以向 C 公開不透明結構,而且需要在 C 中存取任何字串, 複製已解碼訊息緩衝區中的字串。

既有作品和參考資料

DBusCaptn Proto 和 CORBA1 傳送長度 null 終止,protobuf 不會終止。