プログラミング
AOSPソースリリースが遅すぎるため、開発者はバグ報告のためにライブラリを逆アセンブルしている
AOSP Source Releases Are So Late Developers Disassemble Libraries to Report Bugs (github.com)
要約
Android 17のBionic Cライブラリにあるwcscspn()とwcspbrk()関数に、U+0100以上の文字を誤って一致と見なしてしまうバグが発見されました。この問題は、AOSPのソースコードリリースが遅れることで、開発者がバグ報告のためにライブラリを逆アセンブルするという異例の手段を取らざるを得なくなっている状況を浮き彫りにしています。このバグは、絵文字やCJK文字などの非ASCII文字を含む文字列処理を壊し、Visual Pinballなどのアプリケーションに影響を与えています。
全文翻訳
AOSPソースリリースが遅すぎるため、開発者はバグ報告のためにライブラリを逆アセンブルしている
[BUG] bionic: wcscspn()/wcspbrk() は、すべてのwchar_t >= 0x100 を一致として扱います (Android 17, CP3A.260905.009) #2260
新規イシューコピーリンク新規イシューコピーリンクオープンオープン
[BUG] bionic: wcscspn()/wcspbrk() は、すべてのwchar_t >= 0x100 を一致として扱います (Android 17, CP3A.260905.009)#2260コピーリンクラベルバグ説明francisdbが2026年10月12日にオープン
説明
2026年9月リリースされたAndroid 17ビルドでは、wcscspn() および wcspbrk() は、拒否セットの文字がすべて U+0100 未満である場合、文字列中の U+0100 以上の最初の文字で停止します。その文字は、セットに含まれていないにもかかわらず一致として報告されます。wcsspn(), wcschr(), wcsrchr(), wmemchr() および wcsstr() は正しいです。
ASCII区切り文字(改行やワイルドカード文字など)を検索するワイド文字列のコードは、テキストに絵文字、CJK、キリル文字、ギリシャ文字、またはラテン拡張文字が含まれるとすぐに壊れます。
影響を受ける/受けないデバイス
ビルド
結果
Pixel 7
google/panther/panther:17/CP3A.260905.009/16091614:user/release-keys
壊れている
Pixel 8a
google/akita/akita:17/CP3A.260905.009/16091614:user/release-keys (パッチ 2026-09-05)
壊れている
Nothing Phone 2
Nothing/PongEEA/Pong:16/BQ2A.250721.001-BP2A.250605.031.A3 (パッチ 2026-08-01)
OK
公開されている android17-release ソース (android-17.0.0_r1, 2026年6月) は external/llvm-libc から wcscspn/wcspbrk をビルドしますが、これは wchar_t の単純なネストループであり、正しいです。9月のビルドのコードは異なります(「メカニズム」を参照)ので、2026年6月と9月のリリース間にリグレッションが導入されました。
再現手順
NDK (aarch64-linux-android30-clang) でビルドし、/data/local/tmp にプッシュし、adb shell で実行します:
#include <stdio.h>
#include <wchar.h>
int main(void) {
wchar_t s[] = {'a', 0x1F680, 0x100, 'b', 'x', '\n', 0};
printf("wcscspn(s, L\"x\\n\") = %zu (expected 4)\n", wcscspn(s, L"x\n"));
printf("wcspbrk(s, L\"x\\n\") = index %ld (expected 4)\n", (long)(wcspbrk(s, L"x\n") - s));
printf("wcsspn(s, L\"a\\U0001F680\") = %zu (expected 2)\n", wcsspn(s, L"a\U0001F680"));
return 0;
}
CP3A.260905.009 での出力:
wcscspn(s, L"x\n") = 1 (expected 4)
wcspbrk(s, L"x\n") = index 1 (expected 4)
wcsspn(s, L"a\U0001F680") = 2 (expected 2)
U+0001 から U+10FFFF までのすべてのコードポイント(サロゲートとセットの2つのメンバーを除く)を wcscspn(L"<cp>\n", L"x\n") でスキャンすると、1,111,808 のコードポイントで 1 の代わりに 0 が返されます。U+0100 から U+10FFFF までのすべてのコードポイントです。U+0001 から U+00FF は正しいです。
どのセット形状がトリガーするか(すべて Pixel 8a で測定)
拒否セット
結果
1文字
OK
2文字以上、すべて < U+0100 (例: L"x\n", L"\xe9\n")
壊れている
2文字以上、少なくとも1つ >= U+0100
OK
ハヤシ(haystack)を U+0080..U+00FF に制限
OK
メカニズム(出荷された libc.so から)
CP3A.260905.009 の /apex/com.android.runtime/lib64/bionic/libc.so の wcscspn の逆アセンブルは、セットによって選択される3つのパスを示しています:
1文字: 単純な比較ループ。正しい。
2文字以上: スタック上の256バイトのブールテーブルがセットから埋められます。セットの文字は 1..0xFF の範囲です。セットの文字が >= 0x100 の場合、関数は各ハヤシ文字に対して wcschr() を呼び出すフォールバックを行います。正しい。
それ以外の場合、ハヤシはテーブルに対してスキャンされます:
a2564: ldrb w8, [x9, x8] ; table[c]
a2568: tbnz w8, #0, a2578 ; セット内 -> 停止 (正しい)
a256c: ldr w8, [x22, #0x4]! ; 次の文字
a2570: cmp w8, #0x100
a2574: b.lo a2564 ; c < 0x100 -> スキャンを続ける
a2578: ... ; c >= 0x100 -> 停止、一致として報告
U+0100 以上の文字は、メンバーがすべて U+0100 未満のセットには含まれないため、wcscspn ではスキャンを続行する必要があります。コードは代わりに停止します。
wcsspn は同じ構造を持ち、そこで停止することは正しい答えです(文字はキープセットに含まれていません)。そのため、補関数のみが間違っています。wcspbrk はこのスキャン上に実装されており、バグを継承します。
既存の bionic テスト TEST(wchar, wcspbrk) は tests/wchar_test.cpp で ASCII 入力のみを使用しているため、これをキャッチしません。EXPECT_EQ(3u, wcscspn(L"aĀb\n", L"x\n")) のようなテストはキャッチするでしょう。
実世界への影響
Android 上の Visual Pinball (libwinevbs、Wine の vbscript エンジンの Unix ビルド) は、9月のアップデート後に絵文字を含むコメントを VBScript ソースに含むテーブルのロードを停止しました。lexical analyzer は wcspbrk(ptr, L"\n\r") を使用してコメントをスキップしていましたが、行末ではなく最初の絵文字の位置を取得し、「無効な文字」を報告しました。
FileSystem.MoveFolder も同様に、wcspbrk(src, L"*?><") を介して、U+0100 以上の文字を含むパスをワイルドカードパターンとして扱いました。
呼び出しを単純なループに置き換えることで、下流で回避策が適用されました: vpinball/libwinevbs#41 (vpinball/vpinball@e7837322f4 で出荷済み)。
影響を受ける関数の完全な逆アセンブルとプローブソースは、要求に応じて利用可能です。
私はサポートされているNDKを使用しています
私が使用しているNDKは現在サポートされていることを確認しました
影響を受けるバージョン
r29
リアクションは現在利用できません
アクティビティ
francisdbが2026年10月12日にバグを追加しました
enh-googleが2026年10月12日にコメントしました
enh-google
2026年10月12日
コラボレーター
その他のアクション
はい、すべて正しそうです。そして、まだ ToT で問題になっているようです。(「ソースを見ればいいだけじゃない?」と言おうと思ったのですが、android-latest-release はまだこれらの4月の変更のどれも含まれていないほど古いようです :-(
wcspbrk() は、それが単に __attribute__((__flatten__)) wchar_t* wcspbrk(const wchar_t* s, const wchar_t* delims) { size_t i = wcscspn(s, delims); if (s[i] != L'\0') return const_cast<wchar_t*>(s) + i; return nullptr; } だからです。しかし、両方の不足しているテストを追加します。そして理想的には、非ASCIIを実際に使用するテストがどこにも欠けていないかを見つけようとします。
また、影響を受けるデバイスの数を最小限に抑えるために、修正をバックポートできるかどうかも確認します。(これは、直接関係のないテストを別の後続の変更で追加することを保証する理由になるでしょう。)
😕リアクション
😕10
Joaquín Vacas Verísimo, Kunal Agrawal, Vinayak, Doug Lynch, Matheus Araújo, David Allison, LifeIsStrange, JannF, Alexander Pushkov, Oliver Krieg がリアクションしました
👀リアクション
👀3
Joaquín Vacas Verísimo, Doug Lynch, David Allison がリアクションしました
enh-googleが2026年10月12日にコメントしました
enh-google
2026年10月12日
コラボレーター
その他のアクション
ああ、さらに恥ずかしいことに、wcscspn() の既存のテストがあります。それは単に間違っています:
[ RUN ] wchar.wcscspn
bionic/tests/wchar_test.cpp:(1475)
Failure in test wchar.wcspbrk
Expected equality of these values:
2u
Which is:
2
wcscspn(L"he\ufffelo", L"lo")
Which is:
3
wchar.wcspbrk exited with exitcode 1.
🤦
😕リアクション
😕1
Joaquín Vacas Verísimo がリアクションしました
👀リアクション
👀1
Joaquín Vacas Verísimo がリアクションしました
francisdbが2026年10月13日にコメントしました
francisdb
2026年10月13日
著者
その他のアクション
迅速な対応ありがとうございます。ソースが(まだ)利用できないのは確かに残念です。
joaquinvacasが2026年10月13日にコメントしました
joaquinvacas
2026年10月13日
その他のアクション
ドラマチックに聞こえるかもしれませんが、そうではありません。ただ心配しているのです。何かがおかしいと感じます... GoogleがAOSPソースコードを閉鎖することを決定して以来、多くの問題が修正なしで発生しており、Google側からの透明性はありません...これがどのように管理されるかについて、何か動きはありますか?つまり、このバグではなく、AOSPプロジェクトの管理に関する問題です。
👍リアクション
👍18
MasterMann, Marcin Panniak, Terence Eden, Ben Parsons, p12h4, Björn Kettunen, Marcos Del Sol Vives, Braden Farmer, Max Rumpf, Agustín および 8 名がリアクションしました
pirama-arumuga-nainarが2026年10月13日にコメントしました
pirama-arumuga-nainar
2026年10月13日
コラボレーター
その他のアクション
これがどのように管理されるかについて、何か動きはありますか?つまり、このバグではなく、AOSPプロジェクトの管理に関する問題です。
source.android.com(特に、https://source.android.com/docs/whatsnew/site-updates?year=2026#aosp-changes)にこのトピックに関する公式なコミュニケーションがあります。
(「ソースを見ればいいだけじゃない?」と言おうと思ったのですが、android-latest-release はまだこれらの4月の変更のどれも含まれていないほど古いようです :-(
参考までに、android-latest-release はマニフェストブランチであり、android17-release は git br