AOSP Source Releases Are So Late Developers Disassemble Libraries to Report Bugs

On Android 17 builds from September 2026, wcscspn() and wcspbrk() stop at the first character of the string that is >= U+0100 whenever the reject set has two or more characters that are all < U+0100. The character is reported as a match even though it is not in the set. wcsspn(), wcschr(), wcsrchr(), wmemchr() and wcsstr() are correct.

在 2026 年 9 月的 Android 17 版本中,当拒绝集合(reject set)包含两个或以上均小于 U+0100 的字符时,wcscspn() 和 wcspbrk() 会在字符串中第一个大于或等于 U+0100 的字符处停止。即使该字符不在集合中,它也会被报告为匹配项。而 wcsspn()、wcschr()、wcsrchr()、wmemchr() 和 wcsstr() 则工作正常。

Any code that scans wide strings for ASCII delimiters, for example newline or wildcard characters, breaks as soon as the text contains an emoji, CJK, Cyrillic, Greek or Latin Extended character.

任何扫描宽字符串以查找 ASCII 分隔符(例如换行符或通配符)的代码,一旦文本中包含表情符号、中日韩统一表意文字(CJK)、西里尔字母、希腊字母或拉丁语扩展字符,就会出现故障。

The public android17-release sources (android-17.0.0_r1, June 2026) build wcscspn/wcspbrk from external/llvm-libc, which is a plain nested loop over wchar_t and is correct. The code on the September builds is different (see “Mechanism”), so the regression was introduced between the June and September releases.

公开的 android17-release 源码(android-17.0.0_r1,2026 年 6 月)通过 external/llvm-libc 构建 wcscspn/wcspbrk,其实现是针对 wchar_t 的简单嵌套循环,且逻辑正确。9 月版本的代码有所不同(参见“机制”部分),因此该回归问题是在 6 月至 9 月的版本发布期间引入的。

Build with the NDK (aarch64-linux-android30-clang), push to /data/local/tmp, run with adb shell:

使用 NDK (aarch64-linux-android30-clang) 进行构建,推送到 /data/local/tmp,并通过 adb shell 运行:

Output on CP3A.260905.009:

CP3A.260905.009 上的输出:

A sweep of every code point from U+0001 to U+10FFFF (skipping surrogates and the two set members) with wcscspn(L”\n”, L”x\n”) returns 0 instead of 1 for 1,111,808 code points: every one from U+0100 to U+10FFFF. U+0001 to U+00FF are correct.

对从 U+0001 到 U+10FFFF 的每个码点(跳过代理项和两个集合成员)使用 wcscspn(L”\n”, L”x\n”) 进行扫描,结果显示 1,111,808 个码点返回了 0 而非 1:即从 U+0100 到 U+10FFFF 的每一个码点。U+0001 到 U+00FF 的结果是正确的。

Which set shapes trigger it (all measured on the Pixel 8a):

触发该问题的集合形式(均在 Pixel 8a 上测得):

Disassembly of wcscspn in /apex/com.android.runtime/lib64/bionic/libc.so on CP3A.260905.009 shows three paths selected by the set:

对 CP3A.260905.009 上 /apex/com.android.runtime/lib64/bionic/libc.so 中的 wcscspn 进行反汇编,显示了由集合选择的三条路径:

A character >= 0x100 cannot be in a set whose members are all < 0x100, so for wcscspn the scan must continue past it. The code stops instead. wcsspn has the same structure, and there stopping is the correct answer (the character is not in the keep set), which is why only the complement functions are wrong. wcspbrk is implemented on top of this scan and inherits the bug.

大于或等于 0x100 的字符不可能存在于成员均小于 0x100 的集合中,因此对于 wcscspn,扫描必须跳过该字符继续进行。但代码却停止了。wcsspn 具有相同的结构,在那里停止是正确的(因为该字符不在保留集合中),这就是为什么只有补集函数出错的原因。wcspbrk 是基于此扫描实现的,因此也继承了这个错误。

The existing bionic test TEST(wchar, wcspbrk) in tests/wchar_test.cpp only uses ASCII input, so it does not catch this. A test such as EXPECT_EQ(3u, wcscspn(L”aĀb\n”, L”x\n”)) would.

现有的 bionic 测试 TEST(wchar, wcspbrk)(位于 tests/wchar_test.cpp 中)仅使用 ASCII 输入,因此无法捕获此问题。像 EXPECT_EQ(3u, wcscspn(L”aĀb\n”, L”x\n”)) 这样的测试则可以。

Visual Pinball on Android (libwinevbs, a Unix build of Wine’s vbscript engine) stopped loading any table whose VBScript source contains a comment with an emoji after the September update: the lexer uses wcspbrk(ptr, L”\n\r”) to skip comments, got the position of the first emoji instead of the line end, and reported “Invalid character”. FileSystem.MoveFolder likewise treated every path containing a character >= U+0100 as a wildcard pattern via wcspbrk(src, L”*?><”).

Android 版 Visual Pinball(libwinevbs,Wine 的 vbscript 引擎的 Unix 构建版本)在 9 月更新后,无法加载任何 VBScript 源码中包含带表情符号注释的表格:词法分析器使用 wcspbrk(ptr, L”\n\r”) 来跳过注释,结果获取到了第一个表情符号的位置而非行尾,并报告了“无效字符”。同样,FileSystem.MoveFolder 也通过 wcspbrk(src, L”*?><”) 将每个包含大于或等于 U+0100 字符的路径视为通配符模式。

Worked around downstream by replacing the calls with plain loops: vpinball/libwinevbs#41 (shipped in vpinball/vpinball@e7837322f4).

下游通过将这些调用替换为普通循环来规避此问题:vpinball/libwinevbs#41(已在 vpinball/vpinball@e7837322f4 中发布)。

Full disassembly of the affected functions and the probe sources are available on request.

受影响函数的完整反汇编代码和探测源码可按需提供。

yeah, that all sounds correct, and seems to still be an issue at ToT.

是的,这些听起来都正确,而且在 ToT(最新代码树)中似乎仍然存在这个问题。

(i was going to say “you know you can just look at the source?”, but android-latest-release seems to still be too old to have any of these changes from april :-( )

(我本来想说“你知道你可以直接看源码吗?”,但 android-latest-release 似乎太旧了,还没有包含四月份以来的任何更改 :-( )

wcspbrk() is affected because it’s just

wcspbrk() 受到影响,因为它只是

but i’ll add both missing tests, and ideally try to see if i can find everywhere else we’re missing a test that actually uses non-ascii!

但我会把这两个缺失的测试补上,并且理想情况下,我会尝试找出其他所有缺少非 ASCII 测试的地方!

i’ll also see if i can get the fix backported to minimize the number of affected devices. (which is probably a reason to ensure any not-directly-related tests are added in a separate later change.)

我也会看看能否将修复程序向后移植,以尽量减少受影响设备的数量。(这可能也是确保任何非直接相关的测试在后续单独更改中添加的原因。)

gah, even more embarrassing is that we do have an existing test for wcscspn(), it’s just wrong:

天哪,更尴尬的是,我们确实有一个针对 wcscspn() 的现有测试,只是它写错了:

Thanks for the quick response. It’s indeed unfortunate that the source is not available (yet).

感谢快速回复。源码(目前)还不可用,这确实很遗憾。

Sorry if it sounds dramatic, because it’s not. I’m just worried. Something feels wrong with this…

如果听起来有些夸张,我很抱歉,因为我并非此意。我只是感到担忧。这感觉有些不对劲……

Since Google decided to close AOSP source code, a lot of issues have been flourishing without any kind of fix, and there’s no transparency from the Google part…

自从谷歌决定关闭 AOSP 源码以来,许多问题不断涌现却没有任何修复,而且谷歌方面也没有任何透明度……

Is there any movement regarding how this is going to be managed? I mean, not this bug, but the issues regarding the management of the AOSP project.

关于这方面将如何管理,有什么进展吗?我的意思是,不是指这个 Bug,而是指关于 AOSP 项目管理的问题。

source.android.com (in particular, https://source.android.com/docs/whatsnew/site-updates?year=2026#aosp-changes) has official communication on this topic.

source.android.com(特别是 https://source.android.com/docs/whatsnew/site-updates?year=2026#aosp-changes)上有关于此主题的官方说明。

FWIW, android-latest-release is a manifest branch, and android17-release is the git branch. The android 17 sources for bionic are in https://android.googlesource.com/platform/bionic/+/refs/heads/android17-release.

顺便提一下,android-latest-release 是一个清单分支,而 android17-release 是 git 分支。Android 17 的 bionic 源码位于 https://android.googlesource.com/platform/bionic/+/refs/heads/android17-release。

Yes, but where is the source code for Android 17 QPR1 which is what is actually running on Pixel and has been stable for over a month…

是的,但是 Android 17 QPR1 的源码在哪里?那才是 Pixel 上实际运行且已经稳定了一个多月的版本……

There must be a better location to discuss these general issues?

一定有更好的地方来讨论这些普遍性问题吧?

Add Oct 14 tech news (incremental scan window 06:13-07:0x UTC Oct 14 …

添加 10 月 14 日科技新闻(增量扫描窗口 10 月 14 日 06:13-07:0x UTC……

yeah, we are not the people who can help you with anything that can’t be fixed in code. but if anyone does have other libc issues or toolchain issues, please file them (as separate bugs!) so we can look at them.

是的,我们无法帮助解决任何无法通过代码修复的问题。但如果有人有其他 libc 问题或工具链问题,请提交它们(作为单独的 Bug!),以便我们查看。

in the meantime, in the spirit of https://sre.google/sre-book/postmortem-culture/ i’ll be making sure we add the missing test, fix the broken test, and run the tests against at least one other libc to make it harder to check in incorrect tests in future.

与此同时,秉承 https://sre.google/sre-book/postmortem-culture/ 的精神,我将确保添加缺失的测试,修复错误的测试,并针对至少另一个 libc 运行这些测试,以防止将来再次提交错误的测试。