Home / Blog / Hardware
Hardware สรุปและวิเคราะห์จากข่าวต้นทาง

Analysis and Review: AOSP Source Release Delayed, Forcing Developers to Decompile Libraries to Report Bugs

Analyze the wcscspn() and wcspbrk() bugs in Android 17 that malfunction with Unicode characters starting at U+0100, and the methods developers use to investigate the issue.

AOSP Releases Source Code Too Slowly, Forcing Developers to Reverse-Engineer Libraries to Debug

Android 17’s September 2026 release contains bugs in wcscspn() and wcspbrk() when they encounter characters starting at U+0100, even when those characters are not in the search set. Developers therefore had to use disassembly from libc.so to trace the execution path, because the source released for the June 2026 version was not the same code.

The impact reached real software such as Visual Pinball on Android, which could not load tables containing emojis in comments, while FileSystem.MoveFolder could interpret paths containing non-ASCII characters as wildcards. Existing bionic tests used ASCII inputs, so they failed to catch this case, even though a wcscspn() test already existed.

When the Source Code Falls Behind the Library in Use

Visual Pinball on Android stopped loading tables containing emojis in comments after the September 2026 update because wcspbrk() found the end-of-line position incorrectly, causing the lexer to report an “Invalid character.”

In this case, the development team did not start with the published source code. They had to trace the symptoms in the real program and then disassemble libc.so, discovering that the library’s execution path stopped at non-ASCII characters even though it should not have. They ultimately applied a temporary fix by replacing the function with a plain loop.

Diagram of the Bug’s Path Through the System Library

A diagram of the path Visual Pinball → wcspbrk() → wcscspn() → bionic libc.so is recommended, showing that wcspbrk() uses the result from wcscspn() in turn.

Divide it into two sides: the June Android 17 source, which uses a plain loop from external/llvm-libc and works correctly, compared with the September binary, which stops immediately when it encounters a character starting at U+0100, even when that character is not in the search set.

Where the Problem Lies in Android’s Release Structure

The gap lies between the public source and the binary actually installed: android-17.0.0_r1 from June uses a nested loop in external/llvm-libc and works correctly, but the September build uses a different codebase and stops when it encounters a character starting at U+0100.

The maintainer also stated that the Android latest release did not keep up with some changes, forcing developers to inspect the disassembly of bionic libc.so and write their own test code to pinpoint the error. The bigger issue is therefore not merely a bug in a function, but how difficult it becomes to investigate problems when the source and binary do not match.

From Inspectable Code to a Binary That Must Be Traced

The Android 17 version released in June uses code from external/llvm-libc, which is an easy-to-read nested loop and works correctly with wcscspn() and wcspbrk().

However, the September version on CP3A.260905.009 had to be examined through the disassembly in bionic/libc.so. This revealed that the code stopped immediately when it encountered a character starting at U+0100, even when that character was not in the search set. Developers had to write their own probe and compare the results with the expected values because the source for the affected code had not yet been published.

A Single Character Causes the Search to Stop at the Wrong Position

Testing with the delimiter set x and a newline produced these results:

FunctionExpected resultResult on CP3A.260905.009
wcscspn()41
wcspbrk()index 4index 1
wcsspn()22

The root cause is that wcscspn() stops immediately when it encounters a character starting at U+0100, even when that character is not in the search set. This affects text containing emojis, CJK, Cyrillic, Greek, or Latin Extended characters. Meanwhile, wcsspn(), wcschr(), wcsrchr(), wmemchr(), and wcsstr() continue to work correctly.

Available Options When the System Library Produces Inconsistent Results

The first option is to rely on the plain loop from external/llvm-libc, which works correctly in the June 2026 Android 17 source. The limitation is that the code in the September release is different, so this does not guarantee identical behavior across every build.

The second option is to continue calling wcscspn() and wcspbrk(), while accepting the risk when text contains characters starting at U+0100 and the search set contains at least two ASCII members. In this situation, the functions may stop at the wrong position.

The final option is to replace the calls with plain loops in the consuming code, following the workaround used by libwinevbs. This fixes the specific issue, but the affected code must be changed manually.

Benefits and Limitations of Disassembling a Library to Confirm a Bug

Inspecting the disassembly clearly identifies the faulty behavior—for example, the code stops immediately when it encounters a wchar_t starting at 0x100, even though that character is not in the search set. This connects the behavior to the real symptoms in Visual Pinball, where emojis cause line parsing and file-path handling to fail.

The limitation is that the investigation requires an Android 17 build, a device, and specific commands such as adb shell. In addition, the source for the affected code was not yet available, requiring extensive use of disassembly and testing to fully confirm the conditions. Disassembling a library is therefore suitable for confirming a problem, but it is not a shortcut for finding the root cause in every case.

The Cost of Testing That Covers Only ASCII

The existing wcspbrk() tests used only ASCII data, so they did not detect problems involving emojis, CJK, or other non-ASCII characters. The existing wcscspn() test also used the wrong case, allowing the regression to reach the September 2026 Android 17 build.

The burden therefore fell on developers, who had to sweep code points from U+0001 through U+10FFFF on a Pixel 8a, inspect the disassembly in libc.so, and run the program through adb shell to verify its behavior. Ultimately, affected projects had to create their own downstream patches by replacing the functions with plain loops, even though the root cause was in the system library.

Lessons to Follow from This Issue

The next steps include adding non-ASCII tests for wcscspn() and wcspbrk(), as well as looking for other areas that still test only ASCII and could miss similar real-world cases.

Another issue is the effort to backport the patch to reduce the number of affected devices. All of this raises a larger question: when AOSP source code is released late, how transparently can developers investigate problems and track their progress?