零初始化記憶體

C 和 C++ 中的未初始化記憶體,是可靠性問題、記憶體安全錯誤和資訊外洩的常見原因。為避免這些問題,Android 會盡可能初始化記憶體。

零初始化的使用者空間記憶體

自 Android 12 起,所有平台原生程式碼 (包括 JNI) 中的堆疊記憶體會初始化為零,所有平台原生程序 (例如 netd) 中的堆積記憶體也會初始化為零,但 zygote 或應用程式中的堆積記憶體不會。

強烈建議使用 NDK 建構的第一方和第三方應用程式使用 -ftrivial-auto-var-init=zero 編譯器旗標,將堆疊的本機變數初始化為零。編譯器會將不必要的零化作業最佳化。例如,當本機變數明確初始化時 (例如,int x = 123; 變數 x 只初始化一次)。如果程式在效能熱點中具有大型堆疊緩衝區,開發人員可以使用編譯器屬性停用初始化作業:

__attribute__((__uninitialized__)) char buf[BUFSIZ];

應用程式也可以使用 android:nativeHeapZeroInitialized 資訊清單屬性,選擇啟用堆積零初始化功能。或者,您也可以使用以下方式,在執行階段控制堆積零初始化程序:

int mallopt(M_BIONIC_ZERO_INIT, level)

其中 level 為 0 或 1。

零初始化的核心記憶體

對於 GKI 核心,核心堆疊和堆積會以零初始化,這是 CDD 強烈建議的做法。

針對堆疊初始化,GKI 會使用 CONFIG_INIT_STACK_ALL_ZERO 設定,這會導致使用 -ftrivial-auto-var-init=zero 編譯器標記建構核心。針對堆初始化,GKI 會使用 CONFIG_INIT_ON_ALLOC_DEFAULT_ON,讓所有頁面堆積、SLAB 和 SLUB 分配在建立時以零值初始化。這個選項實際上類似於將 init_on_alloc=1 傳遞為核心的啟動時間選項。

錯誤報告

我們的工具會產生精闢的錯誤報告,其中包含協助偵錯的額外資訊。額外的配置和取消配置堆疊追蹤功能有助於進一步瞭解特定配置的生命週期,並可更快速地找出記憶體安全性錯誤的根本原因。

記憶體安全性工具產生的錯誤報告範例
圖 1:記憶體安全性工具產生的錯誤報告

開發期間,供應商應檢查 /data/tombstoneslogcat 是否有原生當機問題,以監控是否有錯誤。如要進一步瞭解如何偵錯 Android 原生程式碼,請參閱這裡的資訊。