nodejs / nodejs/node

`TextEncoder.encodeInto()` underfills the destination for some non-ASCII text

Ouverte Adaptée aux débutants
#65,994 2 commentaires 2 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Langage dominant
JavaScript
Étoiles
122k
Forks
37.4k
Merge moyen
4 j 3 h
PR mergées (30 j)
272

Description

There are two problems I found with TextEncoder.encodeInto(), both of which can cause encoding to stall even when the next char can fit the destination.

  1. A 2-byte char requires a 3-byte destination

    const encoder = new TextEncoder();
    const text = '\u0400'.repeat(33);
    
    console.log(encoder.encodeInto(text, new Uint8Array(2)));  // { read: 0, written: 0 }
    console.log(encoder.encodeInto(text, new Uint8Array(3)));  // { read: 1, written: 2 }
    

    The second call proves that '\u0400' should fit into a 2-byte array.

  2. Appending an unread character changes encoding progress

    const encoder = new TextEncoder();
    const text = 'é'.repeat(33);
    
    console.log(encoder.encodeInto(text, new Uint8Array(2)));  // { read: 0, written: 0 }
    console.log(encoder.encodeInto(text + '☺', new Uint8Array(2)));  // { read: 1, written: 2 }
    

    Appending should not change whether preceding chars can be read into the buffer, but there it is.

The bugs were introduced by the encodeInto() performance change in Node.js v25.4.0. The examples above use length 33 strings to exercise that optimized path(kSmallStringThreshold = 32). Unfortunately the current encodeInto.any.js WPT tests fail to expose the problems because:

  1. all input cases use 7 or fewer code units
  2. even then, the cases don't use chars between U+0400 and U+07FF, and
  3. their cases don't contain a narrow dst capacity to reveal the signed-byte problem.

Proposed fixes

src/encoding_binding.cc

  1. Incorrect cutoff in simpleUtfEncodingLength()

    -  if (c < 0x400) return 2;
    +  if (c < 0x800) return 2;
    

    (very likely a typo, given the comment immediately below it says "Code points < 0x800: 2 bytes")

  2. Signed-byte handling in findBestFit()

    -    size_t extra = simpleUtfEncodingLength(data[pos]);
    +    size_t extra = simpleUtfEncodingLength(UTF16 ? data[pos] : static_cast<uint8_t>(data[pos]));
    

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez dans src/encoding_binding.cc, en particulier avec simpleUtfEncodingLength() et findBestFit(), puis examinez la couverture WPT dans encodeInto.any.js. Reproduisez les exemples de 33 caractères et ajoutez une couverture pour U+0400–U+07FF ainsi que pour les destinations étroites ; le travail est terminé lorsque encodeInto indique les valeurs lues/écrites attendues et que les tests WPT concernés passent.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
cpp, javascript, nodejs
Domaine
api, backend
Type d'issue
Bug
Difficulté
2/5
Temps estimé
1-3 heures
Activité
Active
Clarté
Clairement spécifiée
Accessibilité débutants
84/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.