RFC-0034:空值終止字串 | |
---|---|
狀態 | 已遭拒 |
領域 |
|
說明 | 我們提議讓 FIDL 中的字串視為空值 (但目前所有保留字串大小仍與目前的案例相同)。此外,變更 C 繫結,將字串資料使用 uint8_t* |
作者 | |
提交日期 (年-月-日) | 2019-02-08 |
審查日期 (年-月-日) | 2019-02-21 |
拒絕原因
摘要
我們建議:
FIDL 中的字串將是空值 (保留 字串維持原樣;
變更 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:N
,string: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
(更新)EmitLinerarizeMessage
、ProduceInterfaceClientImplementation
等)//sdk/lib/fidl/hlcpp/string.cc
//garnet/public/lib/fidl/rust/fidl/src/encoding.rs
//third_party/go/src/syscall/zx/fidl/encoding.go
(更新日期:marshalString
,unmarshalString
)//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 中存取任何字串, 複製已解碼訊息緩衝區中的字串。
既有作品和參考資料
DBus、Captn Proto 和 CORBA1 傳送長度 null 終止,protobuf 不會終止。
-
CORBA 規格 3.3, 第 2 部分 第 9.3.2.7 節。↩