(Translated by https://www.hiragana.jp/)
Off-by-oneエラー - Wikipedia

Off-by-oneエラー(オフ-バイ-ワンエラー、off-by-one error、OBOE)とは、境界きょうかい条件じょうけん判定はんていかんするエラーの一種いっしゅである。コンピュータプログラミングにおいて、ループただしい回数かいすうよりいちかいおおく、または一回いっかいすくなく実行じっこうされた場合ばあいなどに発生はっせいする。

この問題もんだい代表だいひょうてき原因げんいんとして、プログラマーが数字すうじのカウントを0からではなく1から開始かいししてしまう(おおくのプログラミング言語げんごでは配列はいれつは0からはじまる)、数値すうち比較ひかくにおいて「~未満みまん」とすべきところを「~以下いか」としてしまう、ひとしげられる。また、数学すうがくてき処理しょりおこなっている場合ばあいにも発生はっせいしうる。

配列はいれつじょうのループ

編集へんしゅう

配列はいれつmばん要素ようそからnばんまでの要素ようそ処理しょりする場合ばあいかんがえる。処理しょり対象たいしょう要素ようそはいくつだろうか?この場合ばあい直感ちょっかんてきかんがえるとn-mとなるが、実際じっさいには1個いっこことなり、n-m+1ただしい。これは「さんエラー」の一種いっしゅである。

上記じょうきのような理由りゆうにより、コンピュータじょうかず範囲はんい表現ひょうげんする場合ばあいにはしばしば半開はんかい区間くかんもちいられる。mnふく区間くかんは、植木うえきさんエラーをけるためにmふくn+1ふくまない区間くかんとして表現ひょうげんされる。たとえば、5かいかえして実行じっこうされるループは0から5までのひだり半開はんかい区間くかんもちいて以下いかのように表現ひょうげんされる。

for (i = 0; i < 5; i++) {
    /* ループちゅう処理しょり */
}

ループちゅう処理しょり最初さいしょiが0の状態じょうたい開始かいしされる。以降いこうiは1, 2, 3と増加ぞうかし、4までは問題もんだいなく実行じっこうされる。つぎ時点じてんiは5となり、条件じょうけんぶんi < 5にせ判定はんていされてループは終了しゅうりょうする。

もし、条件じょうけんぶん使用しようされている比較ひかく演算えんざん<=(「~未満みまん」ではなく「~以下いか」)だった場合ばあい、ループのなか処理しょりは6かい実行じっこうされてしまう。つまり、iは0, 1, 2, 3, 4, 5と増加ぞうかし、5まで実行じっこうされる。同様どうように、iが0でなく1で初期しょきされていた場合ばあいにはループは4かいしか実行じっこうされない。つまり、iは1, 2, 3と増加ぞうかし、4まで実行じっこうされる。これらのケースはどちらもoff-by-oneエラーの一種いっしゅである。

このようなエラーが発生はっせいするほかれいとしては、whileぶん使用しようすべきところでdo-whileぶん使用しようした場合ばあいぎゃくおなじ)がげられる。do-whileループはかならず1かい実行じっこうされる。

配列はいれつ関連かんれん勘違かんちがいはプログラミング言語げんごごとの差異さい由来ゆらいする場合ばあいもある。配列はいれつは0からはじまる場合ばあい一般いっぱんてきだが、1からはじまる言語げんごもいくつかある。Pascalでは配列はいれつをユーザが指定していした数字すうじからはじめることができるが、これにより配列はいれつ問題もんだいのドメインにわせて設定せっていすることができる。

植木うえきさんエラー

編集へんしゅう
 
区間くかんn区切くぎるにはn+1のフェンスが必要ひつようになる

植木うえきさんエラーはoff-by-oneエラーの一種いっしゅであり、「支柱しちゅう(fencepost)エラー」、「電柱でんちゅう(telegraph pole)エラー」、「電灯でんとう(lamp-post)エラー」ともばれる。このエラーは以下いか問題もんだい説明せつめいされる。

100メートルのフェンスをつくり、10メートルごとにフェンスの支柱しちゅうてる場合ばあい必要ひつよう支柱しちゅう本数ほんすうなんほんか?

直感ちょっかんてきかんがえると、100÷10=10であるため10ほんというこたえになるが、これはあやまりである。フェンスは10の区間くかん区切くぎられるが、支柱しちゅうは11ほん必要ひつようとなる。

また、まれに、入力にゅうりょく予期よきしない規則きそくせいがあった場合ばあいのエラーが"植木うえきさんエラー"とばれることもある。これは、たとえば理論りろんじょう効率こうりついはずの分木ぶんぎハッシュ関数かんすう特定とくてい入力にゅうりょくによってまるでだめになってしまうことをしている。このエラーは、アルゴリズム期待きたいされているいと最悪さいあく場合ばあいいとのによって発生はっせいする。

セキュリティとの関連かんれん

編集へんしゅう

off-by-oneエラーのうちセキュリティに関係かんけいしたバグとなる典型てんけいてきれいは、libcstrncat関数かんすう使用しようほうあやまりによるものである。strncat関数かんすうかんするよくある誤解ごかいとしては「連結れんけつした文字もじれつ終端しゅうたんのnull文字もじしたながさは引数ひきすう指定していした最大さいだいちょうえることはない」というものがある。実際じっさいには、終端しゅうたんのnull文字もじふくめると、指定していした最大さいだいちょうより1文字もじおおみがおこなわれる。以下いかのコードはこのたねのバグをふくんでいる。

void foo (char *s) {
    char buf[15];
    memset(buf, 0, sizeof(buf));
    strncat(buf, s, sizeof(buf)); // 最後さいご引数ひきすうは sizeof(buf)-1 でなければならない
    return;
}

システムによっては(とくリトルエンディアンのアーキテクチャの場合ばあい)、このバグによってフレームポインタ最下位さいかいのバイトが上書うわがきされてしまうことがある。攻撃こうげきしゃはこれを利用りようしてちゅうのルーチンのローカル変数へんすうえられるため、このバグはセキュリティホールとなることがある。

参考さんこう文献ぶんけん

編集へんしゅう
  • この記事きじ初期しょきのバージョンはFOLDOC記事きじ fencepost errorもとづいています。

関連かんれん項目こうもく

編集へんしゅう

外部がいぶリンク

編集へんしゅう