MEM11-C. ヒープ領域が無限にあると想定しない
メモリは限定されたリソースで使い果たされてしまう可能性がある。使用可能なメモリは、通常は、物理メモリ量と管理者によってオペレーティングシステムに割り当てられたスワップ領域の合計までに限られている。たとえば、2GB のスワップ領域が構成され、1GB の物理メモリがあるシステムでは、すべての実行中のプロセスに対して最大で合計 3GB のヒープ領域を割り当てることができる (オペレーティングシステム自体のサイズと実行中のすべてのプロセスのテキストおよびデータセグメント分は引かれる)。すべての仮想メモリを割り当てると、さらなるメモリ要求は失敗する。「MEM32-C. メモリ割り当てエラーを検出し、対処する」で説明されている通り、チェックに失敗したプログラムや適切なメモリ割り当て処理に失敗したプログラムは未定義な動作となり、ヒープ領域が使い果たされるとクラッシュする可能性がある。以下の場合にヒープが使い果たされる可能性がある。
- メモリリーク
- 無限ループ
- プログラムが、デフォルトのヒープ量よりも多いメモリを要求している
- 一般的なデータ構造体 (たとえば、ハッシュテーブル、ベクタなど) の間違った実装
- おそらく他のプロセスが原因でシステムメモリ全体が使い果たされた
- プロセスのデータセグメントが最大サイズを超えた
malloc()
は、要求されたメモリを返せない場合に NULL
を返す。
しかし、メモリ割り当ての失敗をチェックして処理すれば十分かというと、そうとも言えない。長期に渡って実行されるサーバプログラムで大規模なデータを取り扱う場合などは、ヒープなどのシステムリソースが枯渇するような状況においても、サービスを提供できるように設計しておく必要がある。ディスクスペースやデータベースなど、別の記憶デバイスを活用することは、このようなシステムでは不可欠である。
違反コード
以下のコードは、要求されるメモリ領域に上限を設けておらず、プログラムは容易にヒープを使い果たす可能性がある。
使用可能なメモリ領域がない状況でヒープが消費され続けると、ヒープエラーが発生する。
#include <stdio.h> #include <string.h> #include <stdlib.h> enum {MAX_LENGTH=100}; typedef struct namelist_s { char name[MAX_LENGTH]; struct namelist_s* next; } *namelist_t; int main() { namelist_t names = NULL; char new_name[MAX_LENGTH]; do { /* 未知の数のレコードをリストに追加 ユーザは好きなだけデータを入力してヒープも使い果たしてしまうおそれがある */ puts("To quit, enter \"quit\""); puts("Enter record:"); fgets(new_name, MAX_LENGTH, stdin); if (strcmp(new_name, "quit") != 0) { /* ヒープサイズを気にせずに、名前を追加し続ける */ unsigned int i = strlen(new_name) - 1; if (new_name[i] == '\n') new_name[i] = '\0'; namelist_t new_entry = (namelist_t) malloc(sizeof( struct namelist_s)); if (new_entry == NULL) { /* エラー処理 */ } strcpy( new_entry->name, new_name); new_entry->next = names; names = new_entry; } puts(new_name); } while (strcmp( new_name, "quit") != 0); return 0; }
適合コード
プログラムで取り扱うオブジェクトやデータ構造体がヒープを使い果たしてしまうほど大きい場合、データベースの使用を検討し、レコードが適宜ディスクに書き込まれることと、データ構造がヒープ領域より大きくならないことを保証するべきだ。
前出の違反コードの例では、ユーザは 1 つの long 変数を再利用して入力を格納することができる。そしてその値を
userID
とその他の必要なフィールドのある User
テーブルを含んでいる簡単なデータベースに書き込むことができる。これによって、ヒープが使い果たされることがなくなる。
リスク評価
静的分析ツールはヒープを使い果たす可能性のあるコードを特定できないため、本レコメンデーションの違反を指摘するのは難しい。また、ヒープサイズは実行時環境によって異なる。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
MEM11-C |
低 |
中 |
高 |
P2 |
L3 |
関連するガイドライン
CERT C++ Secure Coding Standard | MEM12-CPP. Do not assume infinite heap space |
CERT Oracle Secure Coding Standard for Java | MSC05-J. Do not exhaust heap space |
MITRE CWE | CWE-770, Allocation of resources without limits or throttling |
翻訳元
これは以下のページを翻訳したものです。
MEM11-C. Do not assume infinite heap space (revision 30)