A Width Check Broke a Kanji

Satu nama dimasukkan ke dalam jadual terminal dan keluar dalam keadaan rosak. Nama keluarga tersebut ialah 𠮷田.

Watak pertama bukanlah 吉 yang biasa. Ia adalah 𠮷 (U+20BB7). Ini adalah bentuk jarang yang digunakan dalam nama keluarga Jepun yang sebenar. Jadual tersebut memendekkan sel untuk memuatkan lajur. Bukannya nama, ia mencetak watak yang rosak. Kanji tersebut terbelah dua.

Pepijat ini wujud dalam satu baris pintasan (shortcut). Kod tersebut memutuskan bahawa sesuatu rentetan selamat untuk dipotong mengikut indeks sebelum ia benar-benar dipendekkan. Logik ini gagal disebabkan cara JavaScript mengendalikan rentetan.

Satu rentetan JavaScript mempunyai tiga jenis panjang yang berbeza:

  • Panjang unit kod: "𠮷".length ialah 2. Ini mengira unit UTF-16.
  • Bilangan titik kod: [..."𠮷"].length ialah 1. Ini mengira watak sebenar.
  • Lebar paparan: Bilangan lajur yang diambil dalam terminal ialah 2.

Bagi teks bahasa Inggeris biasa, nombor-nombor ini adalah sama. "abc" mempunyai 3 unit, 3 titik, dan 3 lajur. Kebanyakan kod menganggap kebetulan ini sebagai satu peraturan.

Watak 𠮷 melanggar peraturan tersebut. Ia mempunyai 2 unit kod dan 2 lajur. Nombornya sepadan, tetapi atas sebab yang berbeza. Kod tersebut melihat 2 sama dengan 2 dan menggunakan laluan pantas (fast path) untuk memotong rentetan mengikut indeks.

Apabila ia memotong rentetan pada indeks 3, ia mengambil watak pertama sepenuhnya dan hanya separuh daripada watak kedua. Ini meninggalkan 'surrogate' yang terasing. Terminal memaparkannya sebagai kotak yang rosak.

Watak Jepun biasa seperti 漢 adalah selamat. Ia mempunyai 1 unit kod dan 2 lajur. Oleh kerana 1 tidak sama dengan 2, kod tersebut mengelakkan pintasan yang rosak itu. Pepijat ini hanya menjejaskan watak jarang dan emoji.

Untuk membaiki ini, anda mesti:

  • Lindungi laluan pantas untuk menolak rentetan dengan high surrogates