Contexte du bug

Depuis les builds d’octobre 2026 d’Android 17, les fonctions wcscspn() et wcspbrk() de la bibliothèque bionic renvoient un faux positif dès qu’un wchar_t supérieur ou égal à 0x100 apparaît dans la chaîne analysée, à condition que l’ensemble de rejet contienne au moins deux caractères strictement inférieurs à U+0100. Le problème ne touche pas les fonctions apparentées wcsspn(), wcschr(), wcsrchr(), wmemchr() et wcsstr(), qui restent conformes aux spécifications.

Mécanisme introduit

Les sources publiques d’Android 17 (android-17.0.0_r1, juin 2026) compilent wcscspn et wcspbrk depuis external/llvm-libc. Cette implémentation repose sur une boucle imbriquée qui compare chaque caractère de la chaîne d’entrée à chaque caractère du jeu de rejet, sans aucune optimisation de type de caractère. Entre les versions de juin et de septembre 2026, le code a été remplacé par une version propriétaire de bionic qui introduit une optimisation basée sur la valeur du point de code : tout wchar_t ≥ 0x100 est immédiatement considéré comme une correspondance, même si le jeu de rejet ne le contient pas. Cette logique, probablement destinée à accélérer le traitement des caractères ASCII, ignore les caractères Unicode étendus (emoji, CJK, Cyrillic, Greek, Latin Extended), entraînant une rupture de la recherche de délimiteurs ASCII comme \n ou 'x'.

Impact sur les applications

Les applications qui utilisent les fonctions concernées pour analyser des chaînes larges – typiquement pour détecter des séparateurs de lignes, des caractères génériques ou des fins de champ – s’interrompent dès la première occurrence d’un caractère Unicode supérieur à U+00FF. Le problème se manifeste sur plusieurs appareils :

Device          Build                                 Result
Pixel 7         google/panther/panther:17/CP3A.260905.009/broken
Pixel 8a        google/akita/akita:17/CP3A.260905.009/broken (patch 2026-09-05)
Nothing Phone 2 Nothing/PongEEA/Pong:16/BQ2A.250721.001‑BP2A.250605.031.A3 (patch 2026-08-01) ok

Les développeurs doivent donc désassembler les bibliothèques bionic pour identifier la régression, car les sources officielles ne sont publiées que plusieurs mois après les builds. Cette contrainte ralentit le cycle de correction et augmente le risque de livrer des applications défectueuses aux utilisateurs finaux.

Reproduction et perspectives de correction

Un exemple minimal reproduisant le comportement erroné utilise le NDK aarch64‑linux‑android30‑clang :

#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"));
    return 0;
}

Sur les builds affectés, la sortie indique 1 au lieu de 4, confirmant que le caractère emoji (0x1F680) déclenche prématurément la correspondance. La correction passe par la restauration de l’implémentation originale de llvm‑libc ou par l’ajout d’une condition explicite excluant les points de code ≥ 0x100 lorsqu’ils ne figurent pas dans le jeu de rejet. En attendant un correctif officiel, les développeurs peuvent contourner le problème en pré‑filtrant les chaînes ou en utilisant les fonctions wcsspn et wcschr, qui restent fiables.