低レベルなヒトの覚え書き

●LSI C-86のエラー

2. 「NULL pointer assignment」(と見せかけて、本当はスタックオーバーフロー)


[実験 - その1]

全体の目的は、スタックオーバーフローが発生する実際の様子を観察すること。 具体的には、次の4点に関する観察を目的としました。
1点目は、自動変数の配列のサイズとエラーの関係。
2点目は、自動変数のかわりに静的変数を使用したり、mallocによるメモリの獲得を行なったときの、スタックの様子。
3点目は、1点目の裏返しで、スタックのサイズを増加させたときの様子。
4点目は、コンパイルの際に、スタックオーバーフローの検査を行なうコードを埋め込んだり(lcc.exeの「-h」オプション)、「intlib」をリンクすることの影響。
実験の材料に用いたプログラムをリスト4に示します。

[リスト4]
 | #include<stdio.h>
 | #include<malloc.h>
 | int main() {
 |     /* char A[3000];        *//* パターン1 */
 |     /* static char A[3000]; *//* パターン2 */
 |     /* char *A;             *//* パターン3 */
 |     /* A=malloc(3000);      *//* パターン3 */
 |   A[0]='\0';
 |   printf("stack: %d\n", stackavail());
 |     /* free(A);             *//* パターン3 */
 |   printf("done\n");
 |   return 0;
 | }
◆実験1-1

リスト4のプログラムで「パターン1」の部分を生かしたものを材料として、目的の1番と4番に関する実験を行ないました。 主要な結果は以下のとおり。

[表1]
 ---------------------------------------------------------------
  配列Aのサイズ    コンパイル条件    終了時の様子(スタック残量)
 ---------------------------------------------------------------
      2376          (ノーマル)            正常(114)
                    -h                    正常(126)
                    -lintlib              正常(112)
                    -h, -lintlib          正常(124)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      2377          (ノーマル)            異常
                    -h                    正常??(0124)
                    -lintlib              異常
                    -h, -lintlib          正常(122)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      2380          (ノーマル)            異常
                    -h                    異常
                    -lintlib              異常
                    -h, -lintlib          正常(120)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      2400          (ノーマル)            異常
                    -h                    異常
                    -lintlib              異常
                    -h, -lintlib          異常
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3000          (ノーマル)            異常
                    -h                    「stack overflow」
                    -lintlib              異常
                    -h, -lintlib          「stack overflow」
 --------------------------------------------------------------
   註: プログラム終了時の異常とは、フリーズを基本として、そこに表示の乱れや無関係なエラーメッセージが伴ったり伴わなかったりするもの(不定)。
◆実験1-2

次に、「パターン2」のプログラムと、「パターン3」のプログラムを材料として、目的の2番と4番に関する実験を行ないました(配列Aのサイズは3000に固定)。

[表2]
 --------------------------------------------------------------
  メモリの獲得    コンパイル条件    終了時の様子(スタック残量)
 --------------------------------------------------------------
    static         (ノーマル)             正常(2500)
                   -h                     正常(2496)
                   -lintlib               正常(2498)
                   -h, -lintlib           正常(2494)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    malloc         (ノーマル)             正常(2490)
                   -h                     正常(2502)
                   -lintlib]              正常(2488)
                   -h, -lintlib           正常(2500)
 --------------------------------------------------------------
◆実験1-3

最後に、「パターン1」のプログラムを材料として、目的の3番と4番に関する実験を行ないました(配列Aのサイズは3000に固定)。

[表3]
 ------------------------------------------------------------------
  スタックのサイズ    コンパイル条件    終了時の様子(スタック残量)
 ------------------------------------------------------------------
       3000            (ノーマル)        異常
                       -h                異常
                       -lintlib          異常
                       -h, -lintlib      「stack overflow」
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3110            (ノーマル)        異常
                       -h                異常
                       -lintlib          異常
                       -h, -lintlib      異常
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3120            (ノーマル)        異常
                       -h                異常
                       -lintlib          異常
                       -h, -lintlib      正常(120)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3130            (ノーマル)        異常
                       -h                正常(132)
                       -lintlib          正常(118)
                       -h, -lintlib      正常(130)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3140            (ノーマル)        正常(130)
                       -h                正常(142)
                       -lintlib          正常(128)
                       -h, -lintlib      正常(140)
 ------------------------------------------------------------------
   註: プログラム終了時の異常とは、フリーズを基本として、そこに表示の乱れや無関係なエラーメッセージが伴ったり伴わなかったりするもの(不定)。
◆結果のまとめ

実験1-1と1-3の結果からは、スタックには150バイト程度の余裕がないと危険であることがわかりました(目的1,3)。
実験1-2の結果からは、静的変数やmalloc関数を使用した場合、スタックはほとんど消費されないことが確認されました(目的2)。
また、すべての実験を通じて、コンパイル時の条件がスタックオーバーフローの発生に密接なかかわりを持っていることが確認されました(目的4)。
なかでも、「-h」オプションが必ずしも有効に機能しない場合があることや(実験1-1,1-3)、intlibのリンクがエラーの発生を抑える効果を持つことは(実験1-3)、特に注意を要する点と思われます。

→トップ , →ひとつ上(lsic2)


R.2: 2006/08/01
Copyright (C) 2005,2006 A.Satoshi