プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 7

同カテゴリーの次の記事

プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 8

この記事は、インテル® デベロッパー・ゾーンに公開されている「The Ultimate Question of Programming, Refactoring, and Everything」の日本語参考訳です。


7. ループ内で alloca() 関数を呼び出さない

この問題は、Pixie プロジェクトで見つかりました。このエラーは、次の PVS-Studio 診断によって検出されます。

V505 The ‘alloca’ function is used inside the loop. This can quickly overflow stack. (V505 ‘alloca’ 関数がループ内で使用されています。これは、スタック・オーバーフローを引き起こします。)

inline  void  triangulatePolygon(....) {
  ...
  for (i=1;i<nloops;i++) {
    ...
    do {
      ...
      do {
        ...
        CTriVertex *snVertex =
          (CTriVertex *) alloca(2*sizeof(CTriVertex));
        ...
      } while(dVertex != loops[0]);
      ...
    } while(sVertex != loops[i]);
    ...
  }
  ...
}

説明

alloca(size_t) 関数は、スタックを使用してメモリーを割り当てます。alloca() で割り当てられたメモリーは、関数の終了時に解放されます。

通常、プログラムに割り当てられるスタックメモリーはそれほど大きくありません。Visual C++* でプロジェクトを作成する場合、デフォルトのスタック・メモリー・サイズはわずか 1MB です。そのため、alloca() 関数をループ内で使用すると、利用可能なすべてのスタックメモリーをすぐに消費してしまいます。

上記の例では、3 レベルの入れ子構造のループが使用されています。そのため、大きな多角形に三角法を適用すると、スタック・オーバーフローが発生します。

また、A2W などのマクロには alloca() 関数の呼び出しが含まれているため、ループでこれらのマクロを使用することは安全ではありません。

前述のとおり、デフォルトでは Windows* プログラムは 1MB のスタックを使用します。この値は、プロジェクト設定にある [スタックのサイズの設定] と [スタックのコミット サイズ] で変更できます。詳細は、「/STACK (スタック割り当て)」を参照してください。ただし、スタックサイズを増やすことは、スタック・オーバーフローが発生するタイミングを先延ばしするだけであって、問題の解決にはなりません。

推奨事項

ループ内では、alloca() 関数を呼び出さないようにします。ループで一時バッファーを割り当てる必要がある場合、次のいずれかの方法を使用します。

  1. あらかじめメモリーを割り当てておき、1 つのバッファーをすべての操作で使用します。毎回異なるサイズのバッファーが必要な場合、一番大きなサイズでメモリーを割り当てます。必要なメモリーサイズが不明な場合は、2 つ目の方法を使用します。
  2. ループの本体を別の関数にします。そうすることで、反復ごとにバッファーの作成と破棄が行われます。これも困難な場合は、3 つ目の方法を使用します。
  3. alloca()malloc() 関数または new 演算子に置き換えるか、std::vector などのクラスを使用します。この場合、メモリー割り当てにはより多くの時間がかかります。malloc/new を使用する場合、解放についても考慮する必要があります。これで、大規模なデータでプログラムを実行しても、スタック・オーバーフローが発生しなくなります。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事

  • Parallel Universe マガジンParallel Universe マガジン Parallel Universe へようこそ。 米国インテル社が四半期に一度オンラインで公開しているオンラインマガジンです。インテルの技術者によるテクノロジーの解説や、最新ツールの紹介など、並列化に関する記事を毎号掲載しています。第1号からのバックナンバーを PDF 形式で用意しました、ぜひご覧ください。 12 […]
  • 比較関数の罠比較関数の罠 この記事は、インテル® デベロッパー・ゾーンに公開されている「The Evil within the Comparison Functions」の日本語参考訳です。 この記事の PDF […]
  • 並列プログラミングにおけるロックの効率的な使用並列プログラミングにおけるロックの効率的な使用 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Using Locks Effectively in Parallel Programming […]
  • インテル® IPP サンプル – エラーの修正インテル® IPP サンプル – エラーの修正 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Intel IPP Samples for Windows - error correction」の日本語参考訳です。 この記事は、PVS-Studio を使用することでプログラムがどのように安全になるかを説明した記事の 1 […]
  • マルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発するマルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発する コードの並列化にはさまざまな手法があります。この記事では、インテル® Parallel Composer で利用可能な手法の概要を説明し、各手法の主な長所を比較します。インテル® Parallel Composer は Windows* 上の C/C++ を使用した開発のみを対象としていますが、これらの手法の多くは Fortran や […]