ISO/IEC TS 17961 [insufmem]
Allocating insufficient memory
説明
ルール定義
不十分なメモリの割り当て。1
Polyspace 実装
このチェッカーは以下の問題をチェックします。
キャストに割り当てられた誤ったオブジェクト サイズ。
範囲外にアクセスするポインター。
sizeof において使用された誤った型。
sizeof を誤って使用している可能性があります。
例
キャストに割り当てられた誤ったオブジェクト サイズはポインター変換時にポインターのアドレスが整列していない場合に生じます。ポインターを異なるポインター型に変換する際に、割り当てられたメモリのサイズは変換先のポインターのサイズの倍数でなければなりません。
整列していないポインターをデリファレンスすると、未定義の動作が発生し、プログラムがクラッシュする可能性があります。
ポインター ptr1 を ptr2 に変換するとします。ptr1 が N バイトのバッファーを指し、ptr2 が ポインターで、type *sizeof( が type)n バイトの場合、N が n の整数倍であることを確認します。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
#include <stdlib.h>
void dyn_non_align(void){
void *ptr = malloc(13);
long *dest;
dest = (long*)ptr; //defect
}この例では、ptr から long* への変換に関する欠陥が報告されます。ptr に動的に割り当てられるメモリである 13 バイトは、dest のサイズである 4 バイトの倍数ではありません。この不整列のため、キャストに割り当てられた誤ったオブジェクト サイズの欠陥が生じます。
1 つの修正方法として、変換先のサイズの倍数となるポインター サイズを使用することができます。この例では、割り当てられるメモリを 13 ではなく 12 に変更して欠陥を解決します。
#include <stdlib.h>
void dyn_non_align(void){
void *ptr = malloc(12);
long *dest;
dest = (long*)ptr;
}void static_non_align(void){
char arr[13], *ptr;
int *dest;
ptr = &arr[0];
dest = (int*)ptr; //defect
}この例では、行 6 で ptr を int* に変換する際に欠陥が報告されます。配列 arr のサイズは 13 バイトであるため、ptr のメモリ サイズは 13 バイトです。dest のサイズは 4 バイトで、13 の倍数ではありません。この不整列のため、キャストに割り当てられた誤ったオブジェクト サイズの欠陥が生じます。
1 つの修正方法として、変換先のサイズの倍数となるポインター サイズを使用することができます。この例では、配列 arr のサイズを 4 の倍数に変更して欠陥を解決します。
void static_non_align(void){
char arr[12], *ptr;
int *dest;
ptr = &arr[0];
dest = (int*)ptr;
}#include <stdlib.h>
void *my_alloc(int size) {
void *ptr_func = malloc(size);
if(ptr_func == NULL) exit(-1);
return ptr_func;
}
void fun_non_align(void){
int *dest1;
char *dest2;
dest1 = (int*)my_alloc(13); //defect
dest2 = (char*)my_alloc(13); //not a defect
}この例では、行 11 において my_alloc(13) で返されるポインターを int* に変換する際に欠陥が生じます。my_alloc(13) は動的に割り当てられた 13 バイトのサイズのポインターを返します。dest1 のサイズは 4 バイトで、13 の除数ではありません。この不整列のため、キャストに割り当てられた誤ったオブジェクト サイズの欠陥が生じます。行 12 で、同じ関数呼び出し my_alloc(13) は、dest2 の変換に対し欠陥にはなりません。char* のサイズの 1 バイトが 13 の除数であるためです。
1 つの修正方法として、変換先のサイズの倍数となるポインター サイズを使用することができます。この例では、my_alloc の引数を 4 の倍数に変更して欠陥を解決します。
#include <stdlib.h>
void *my_alloc(int size) {
void *ptr_func = malloc(size);
if(ptr_func == NULL) exit(-1);
return ptr_func;
}
void fun_non_align(void){
int *dest1;
char *dest2;
dest1 = (int*)my_alloc(12);
dest2 = (char*)my_alloc(13);
}範囲外にアクセスするポインターは、ポインターが範囲外でデリファレンスされる場合に発生ます。
ポインターにアドレスが割り当てられると、そのポインターにメモリのブロックが関連付けられます。そのポインターを使用してそのブロック外のメモリにアクセスすることはできません。
範囲外のポインターのデリファレンスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。
修正方法は欠陥の根本原因によって異なります。たとえば、ループ内のポインターをデリファレンスする際、次のいずれかの状況が発生したとします。
ループの上限が大きすぎる。
ポインターをインクリメントするためにポインター演算を使用する際、不適切な値でポインターを進めている。
この問題を修正するには、ループの範囲またはポインターのインクリメント値を変更する必要があります。
多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
int* Initialize(void)
{
int arr[10];
int *ptr=arr;
for (int i=0; i<=9;i++)
{
ptr++;
*ptr=i;
/* Defect: ptr out of bounds for i=9 */
}
return(arr);
}ptr には、サイズ 10*sizeof(int) のメモリ ブロックを指すアドレス arr が割り当てられます。for ループで、ptr は 10 回インクリメントされます。ループの最後の反復で、ptr は割り当てられたメモリ ブロックの外を指します。したがって、デリファレンスはできません。
1 つの修正方法として、ptr のインクリメントとデリファレンスの順序を逆にすることができます。
int* Initialize(void)
{
int arr[10];
int *ptr=arr;
for (int i=0; i<=9;i++)
{
/* Fix: Dereference pointer before increment */
*ptr=i;
ptr++;
}
return(arr);
}最後のインクリメントの後で ptr は割り当てられたメモリ ブロックの外を指しますが、もうデリファレンスされることはありません。
sizeof において使用された誤った型は、以下の条件が両方当てはまる場合に発生します。
メモリ ブロックのアドレスをポインターに代入するか、2 つのメモリ ブロック間でデータを転送します。この代入またはコピーで、
sizeof演算子を使用します。たとえば、
malloc(sizeof(を使用してポインターを初期化するか、type))memcpy(を使用して 2 つのアドレス間でデータをコピーします。destination_ptr,source_ptr, sizeof(type))sizeof演算子の引数に間違った型を使用します。ポインターが指す型ではなく、ポインター型を使用します。たとえば、
ポインターを初期化する際に、type*malloc(sizeof(ではなく、type))malloc(sizeof(を使用します。type*))
type が何型でも、式 sizeof( では常に固定サイズが返されます。返されるサイズは、お使いのプラットフォームでのポインターのサイズ (バイト単位) です。type*)sizeof( の出現は、多くの場合、意図とは異なる使い方を示しています。このエラーにより、必要とするよりもかなり小さなメモリ ブロックの割り当てになり、バッファー オーバーフローなどの脆弱性などにつながる可能性があります。type*)
たとえば、structType が 10 個の int 変数を含む構造体だとします。32 ビット プラットフォームで malloc(sizeof(structType*)) を使用して structType* ポインターを初期化すると、ポインターには 4 バイトのメモリ ブロックが割り当てられます。しかし、1 つの structType 変数全体を割り当てるには、structType* ポインターは sizeof(structType) = 10 * sizeof(int) バイトのメモリ ブロックを指さなければなりません。必要なサイズは、実際に割り当てられた 4 バイトのサイズよりもはるかに大きなサイズです。
ポインターを初期化するには、ポインターの初期化式の type*sizeof( を type*)sizeof( に置き換えます。type)
sizeof による文字配列の割り当て#include <stdlib.h>
void test_case_1(void) {
char* str;
str = (char*)malloc(sizeof(char*) * 5);
free(str);
}この例では、5 つの文字ポインターの malloc を使用して文字ポインター str にメモリを割り当てています。しかし、str は文字を指すポインターであり、文字ポインターを指すポインターではありません。したがって、sizeof の引数 char* は正しくありません。
sizeof の引数と一致させる1 つの修正方法として、引数をポインターの型に一致させることができます。この例では、str は文字ポインターなので引数も文字でなければなりません。
#include <stdlib.h>
void test_case_1(void) {
char* str;
str = (char*)malloc(sizeof(char) * 5);
free(str);
}"sizeof を誤って使用している可能性があります" が発生するのは、Polyspace® Bug Finder™ により sizeof 演算子の使用によるおそらくは想定外の結果が検出される場合です。次に例を示します。
配列のサイズを求めるため、
sizeof演算子が配列パラメーター名で使用されている。しかし、配列パラメーター名それ自体がポインターである。sizeof演算子からは、そのポインターのサイズが返される。配列のサイズを求めるため、
sizeof演算子が配列要素で使用されている。しかし、演算子はその配列要素のサイズを返す。正しくない想定のもとに
sizeof演算子を先に使用したため、特定の関数 (strncmpやwcsncpyなど) の size 引数が不適切になっている。次に例を示します。関数呼び出し
strncmp(string1, string2, num)で、numが、ポインターでのsizeof演算子の誤使用により取得されている。関数呼び出し
wcsncpy(destination, source, num)で、numがワイド文字の数ではなく、sizeof演算子を使用して取得されたバイト単位のサイズとなっている。たとえば、wcsncpy(destination, source, (sizeof(desintation)/sizeof(wchar_t)) - 1)ではなくwcsncpy(destination, source, sizeof(destination) - 1)を使用した場合などです。
sizeof 演算子の不適切な使用は、次の問題の原因となることがあります。
sizeof演算子により配列サイズが返され、その戻り値がループの制限に使用されることを想定している場合に、ループの実行回数が想定より少なくなる。sizeof演算子の戻り値がバッファーの割り当てに使用される場合に、バッファー サイズが必要なサイズより小さくなる。バッファーが不十分だと、結果としてバッファー オーバーフローなどの脆弱性などにつながることがあります。sizeof演算子の戻り値が関数呼び出しで不適切に使用される場合に、関数が想定どおりに動作しない。
考えられる修正方法は次のとおりです。
sizeof演算子を、配列サイズを決定するために配列パラメーター名や配列要素で使用しない。ベスト プラクティスは、配列サイズを別の関数パラメーターとして渡し、そのパラメーターを関数本体で使用することです。
sizeof演算子を慎重に使用して、strncmpやwcsncpyのような関数の数値引数を決定する。たとえば、wcsncpyなどのワイド文字列関数で、バイト数ではなくワイド文字の数を引数として使用します。
sizeof の誤使用#define MAX_SIZE 1024
void func(int a[MAX_SIZE]) {
int i;
for (i = 0; i < sizeof(a)/sizeof(int); i++) {
a[i] = i + 1;
}
}この例では、sizeof(a) は配列サイズではなくポインター a のサイズを返します。
1 つの修正方法として、別の方法を使用して配列サイズを決定します
#define MAX_SIZE 1024
void func(int a[MAX_SIZE]) {
int i;
for (i = 0; i < MAX_SIZE; i++) {
a[i] = i + 1;
}
}チェック情報
| 決定可能性:決定不可能 |
バージョン履歴
R2019a で導入
1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)