コンピューターサイエンス入門:理論編
バッファ範囲チェック
この回でやること
バッファの位置と長さを読み解き、ぴったり収まる範囲とはみ出す範囲を確かめます。
- 読む 約 7 分
- 最後にクイズ 1 問
用意した箱より長いデータを書き込むと、あふれた分は消えてなくなるわけではありません。範囲を自動で検査しない処理では、隣に置いてあった何かを書き換えるおそれがあります。書いた側が気づかず、書き換えられた側が後で困ることもあります。
箱の外まで触らない
固定長のバッファは、メモリ上に取られた連続した領域です。長さ10の箱に先頭から12バイト書けば、後ろの2バイトは箱の外に出ます。Cなどで範囲外へ書き込むと、別の変数や管理用の情報を壊したり、処理が停止したりする可能性があります。結果は保証されません。
書き換えられた値が後で使われると、関係なさそうな場所が壊れます。ログで書き込んだ側が正常に見えても、安全だったとは言えません。
一方、配列などの切り出しは、頼んだ数に届かなくても短い結果を返す場合があります。
Python
data = [0] * 10
print(len(data[8:12])) # 2。4個の指定でも2個だけ
print(data[-1]) # 0。負の番号は末尾を指す[0] * 10 は0を10個並べ、len は要素数を数えます。切り出しの終端12は含みません。これらは範囲外へ書き込む例ではありませんが、エラーが出ないことだけでは、指定した範囲が正しいと判断できない例です。
終端は触る範囲に含めない
先頭からの位置を offset、書くバイト数を length とします。位置は0から数えます。長さが正なら、最後に触る番号は offset + length - 1 です。長さ10の箱の番号は0から9なので、最後の番号が9以下なら収まります。
同じ判定を、触らない終端 offset + length と箱の大きさで比べることもできます。終端が箱の大きさ以下なら収まります。等しい場合も許す点が大切です。
1だけずれる間違いは off-by-one と呼ばれます。ぴったり収まる場合と、1バイトだけはみ出す場合を並べると、境目の読み違いを見つけやすくなります。
書く前に範囲を読む
箱の大きさと位置と長さは、非負の整数として扱います。まず位置が箱の大きさ以下か確かめ、次に長さが「箱の大きさから位置を引いた残り」以下かを比べます。この形なら、位置と長さを足して上限を超える問題を避けられます。
長さ0は何も触りません。この回では、箱の末尾の直後を含め、位置が0から箱の大きさまでなら許す約束にします。通信のヘッダが伝える長さは、実際に届いたデータの大きさとも照合します。
例題で確かめる
長さ16のバッファで、位置12から4バイト書きます。残りは 16 - 12 = 4バイト なので収まります。触る番号は12、13、14、15で、終端16は触りません。長さを5に変えると、残り4を超えて番号16まで触るので拒否します。終端と最後に触る番号を分けて読めば、境目を判断できます。