ensan-hcl/azooKey

[Serious Bug] 学習データが壊れている

Closed this issue · 0 comments

azooKeyでは学習データをLOUDSで管理している。この際、純粋な辞書データに加えて、学習情報を保存するMetadataElementという型を.metadataに出力する。ここには、使われた回数、アップデートの時期などの情報が含まれている。

これまでの実装では、[MetadataElement]のメモリ表現をそのままファイルに出力していた。この際、その長さをMemoryLayout<MetadataElement>.size * count(=5 * count)と見積もっていたが、実際にはこれはMemoryLayout<MetadataElement>.stride * count(=6 * count)と表すべきものであった。

MetadataElementの詳細な型情報は以下の通りである。ここに今回のバグがなかなか検出できなかった理由が隠されている。

struct MetadataElement {
    var lastUsedDay: UInt16
    var lastUpdatedDay: UInt16
    var count: UInt8
}

MetadataElementは実際にはこれを束ねるMetadataBlockという構造体で[MetadataElement]として扱われる。この構造体はルビごとに1つ準備される。つまり、同じルビを共有する学習データがあれば、[MetadataElement]の要素数が増える。しかし、同じルビに複数の要素が学習されることはそう多くない。このため、ほとんどの場合は要素数が1にとどまる。
要素数が1にとどまる場合、size (5)とstride (6)の誤りにもかかわらず、decodeとencodeが完全に成立する。つまり、最後の1バイトがUInt8のcountに対応する。要素数が2に増えるとこの不具合は悪化するため、顕在化する。

本不具合は修正される必要があるが、既存のMetadataElementとの互換性が失われるため、既存の学習データを読み込めなくなる危険性がある。これを回避するには、適切なマイグレーション処理を追加しなければならない。