信頼性の問題やメモリ安全性のバグ、情報漏洩によく見られる原因は、C と C++ で、メモリが初期化されていないことです。この問題を回避するために、Android は可能な限り多くのメモリを初期化します。
ユーザー空間メモリのゼロ初期化
Android 12 以降、すべてのプラットフォーム ネイティブ コード(JNI を含む)でスタックメモリがゼロ初期化され、すべてのプラットフォーム ネイティブ プロセス(netd
など)でヒープメモリがゼロ初期化されますが、zygote
またはアプリではゼロ初期化されません。
NDK でビルドしたファースト パーティ アプリとサードパーティ アプリでは、-ftrivial-auto-var-init=zero
コンパイラ フラグを使用してスタック ローカル変数をゼロ初期化することを強くおすすめします。コンパイラは、不要なゼロ化をなくすように最適化します。これはたとえば、ローカル変数が明示的に初期化される場合(int x = 123;
変数 x
が 1 回だけ初期化されるなど)です。パフォーマンス ホットスポットでプログラムのスタック バッファが大きい場合、デベロッパーは次のコンパイラ属性を使用して初期化を無効にできます。
__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
を渡すこととほぼ同じです。
バグレポート
Google のツールは、デバッグに役立つ補足情報を含む、情報量の多いバグレポートを生成します。追加の割り当てと割り当て解除のスタック トレースにより、特定の割り当てのライフサイクルについてよく理解し、根本原因であるメモリ安全性のバグを大幅に早く発見できます。
開発時に、ベンダーはネイティブ クラッシュについて /data/tombstones
と logcat
を確認し、バグがないか注視する必要があります。Android ネイティブ コードのデバッグについて詳しくは、こちらをご覧ください。