LoginSignup
0
0

More than 1 year has passed since last update.

Rustで実行時にPanic。曰く「byte index 4 is not a char boundary」から始まる異世界狂想曲

Last updated at Posted at 2022-01-07

はじめに

Rust、素敵です。ネイティブコードを吐けるコンパイル言語なのに、こんなに書きやすい。これまでC/C++での悩みだった「コンパイルは通るけど、まともに動かない。つか落ちる」ということがほとんどなく、日常遣いの書き捨てツールでも、ガンガン使えます。うれし。

でも、いくつかハードルがあります。ご存じの通り、借用の概念は身につくまでに多少苦労しますし、OptionとかResultとか、付随してmatchとかtry!とかif letとかにも、慣れるまでちょっとした違和感の谷があります。

ともあれ、「普段使いできるコンパイル言語」って、長い間待ち焦がれてきたものだったので、Rustには感謝しかありません。……でも昨日、ちょっといやーんな場面に出くわしました。

byte index 4 is not a char boundary; it is inside '請' (bytes 3..6) of `申請日時`

落ちた! 落ちたよ! Panicだよ。unwrap()で暫定的に手抜いていたところじゃないよ! とひとしきりワンワン吠えました。

何が起きたか

どういうことが起きたかというと、スライスの境界が文字と文字の間ではなく、ひとつの文字をぶった切るようになってしまった、ということです。ご存じとは思いますが、ASCII文字以外のUTF8の文字って、人間にとっての1文字が、バイト列としては3×nバイトになります。今回の例で言うと、文字とメモリイメージの対応は下図の肌色部分のようになっていまして、それに対して、赤で示した範囲をスライスで取ろうとしたのでPanicしたのです。
image.png
これはガード不能攻撃で、予測不能な入力文字列をStringに入れて、as_str()で中身を覗いてスライスに対して判定をかます、という大変当たり前なコードが、チェックする暇もなく落とされてしまうのです。スライスがResultを返してくれるわけでもないので、そうすると、&strのスライス自体が……詰んでね?

聖典を見る

では、とRust Bookを見ます。章のタイトルに「UTF」が入っているものを検索すれば、すぐに該当の記述は見つけられます。

ここに言及されてはいますが、あまり助けになる説明はありません。軽く絶望します。事前に[u8]にして自力で妥当な切れ目を調べれば回避可能ですが、それも頭が悪そうな気がしますので、もう少しなんとかならないものでしょうか。まあcrate.ioのリンクがあったので、使えそうなcrateを探すことにしました。一応こんなのがあって、書記素に分割してくれるようですが、別に書記素に分けたいわけじゃないんですよね。

暫定解決策と展望もしくは教えてエロい人

単にこの際、&strのスライスは禁じ手にして、chars()イテレータを走査するのがいいのかもしれません。そういうもんなの? 教えてエロい人! ボスケテ……。コンパイラスイッチで&strのスライスをエラーにさせてほしい気分です。当面はchars().collect()で作ったVec<char>に対して、各種文字列処理を行う道具を整えようと思います。割と使うけど自明でない(=作っておく必要がある)のは、cmp, instr, replace, atoi系, toupper系, 全角半角変換, かなカナ変換とか、その辺ですかね。正規表現マッチは自分で書きたくありませんので、そのときはStringに戻しますかね。抽象度の高い正規表現があって、そのままVec<char>にも使えたらいいけど、期待できない気がします。自分で書くのは……車輪の再発明という意味ではDr.STONEなのですが、そそらないです、これは……。

何か、盛大に勘違いしていますか、私は?

太字でうっすら思っていた通り、盛大に勘違いしていました

コメントで教えていただいたので、追記です。上記の通り、太字でうっすら思っていた通り、盛大に勘違いしていました。

fn main() {
    let s = "申請日付";
    println!("{}", s.get(0..3).unwrap_or("ouch"));// 申
    println!("{}", s.get(0..4).unwrap_or("ouch"));// ouch
    ()
}

そんなわけで、getなら、スライスと同じ結果を、Resultに包んで得られるのです。不用意にスライスを使うと危ない、というのは、それはそれとして何か対策が必要な気はしますが、まずは正しいやり方が分かって良かったです。ありがとう、そして、ありがとう。

なお、ハコヅメは第1話は楽しめましたが、第1話なのにテンポというか間合いがもっさりしていて、若干不安が残りました。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0