不適切にデリファレンスされたポインター
ポインターが範囲外でデリファレンスされる
説明
ポインターのデリファレンスに関するこのチェックでは、ポインターが NULL であるか、その境界外を指すかどうか、または動的に割り当てられた後に割り当てを解除されたメモリを指すかどうかが判別されます。チェックは、ポインターをデリファレンスしたときのみ発生し、ポインターにアドレスを割り当てたり、別のポインターに再割り当てしたり、ポインターを関数に渡したりしたときには発生しません。
チェック メッセージには、ポインターのポイント先のサイズ、ポインター オフセット、および割り当てられたバッファーがバイト単位で示されます。"ポイント先のサイズとオフセットの合計がバッファー サイズよりも大きい" 場合、ポインターは範囲外を指します。
ポイント先のサイズ:ポインターをデリファレンスする場合にアクセスするバイト数です。たとえば、
int*型ポインターをデリファレンスする場合、最も一般的なターゲットでアクセスするバイト数は 4 となります。バッファー サイズ:ポインターにアドレスを割り当てると、そのポインターにメモリのブロックが割り当てられます。そのポインターを使用してそのブロック外のメモリにアクセスすることはできません。このブロックのサイズはバッファー サイズです。たとえば、
char変数のアドレスをポインターに代入する場合、割り当てられるバッファー サイズは最も一般的なターゲットで 1 バイトとなります。場合によっては、サイズが明確な値ではなく範囲になる可能性があります。たとえば、サイズの不明な入力を指定して
mallocを使用し、動的にバッファーを作成すると、Polyspace® では、配列サイズは入力データ型で許容される全範囲の値を取り得ると仮定されます。オフセット:ポインター演算を使用して、割り当てられたメモリ ブロック内でポインターを移動できます。ポインターの初期位置と現在の位置の差がオフセットです。
場合によっては、オフセットが明確な値ではなく範囲になる可能性があります。たとえば、ループ内で配列にアクセスすると、オフセットはループの反復ごとに値を変更し、ループ全体を通じて値の範囲を取ります。
たとえば、ポインターが配列を指す場合、
バッファー サイズは配列サイズです。
オフセットは配列の先頭とポインターの現在の位置の差です。

このチェックでは [ターゲット プロセッサ タイプ] (-target) の指定を使用して、データ型のサイズを判別します。
このチェックの診断
例
int main() {
short x=0;
int *ptr = (int *) &x;
*ptr = 2;
return 0;
}この例では、変数 x のデータ型は short です。このデータ型は、ほとんどのターゲットで 2 バイトのバッファー サイズに相当します。
ただし、このバッファーのアドレスは int* 型ポインター ptr にキャストされます。int* 型ポインターは、ほとんどのターゲットでサイズが 4 バイトのバッファーを指します。ptr のデリファレンスには、これらの 4 バイトへのアクセスが必要になります。元の割り当ては 2 バイトのみであったため、ポインターのデリファレンスにより、許容範囲外のアクセスとなります。したがって、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 2 バイトのバッファー内でオフセット 0 にある 4 バイトを指しているため、範囲外であることが確認されます。
"ポイント先のサイズ" は 4 バイトです。これは、ポインター
ptrがintを指しているためです。"バッファー サイズ" は 2 バイトです。これは、バッファー サイズは指されている変数である
xの型に基づくためです。xの型はshortです。"オフセット" は 0 です。これは、ポインターがバッファーの先頭を指しているためです。ポインター演算は関与しません。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
#define Size 1024
int input(void);
void main() {
int arr[Size];
int *p = arr;
for (int index = 0; index < Size ; index++, p++){
*p = input();
}
*p = input();
}この例では以下のようになります。
forループの前では、pは配列arrの先頭を指します。forループの後では、pは配列の外部を指します。
for ループ後の p のデリファレンスに対し、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 4096 バイトのバッファー内でオフセット 4096 にある 4 バイトを指しているため、範囲外であることが通知されます。
"ポイント先のサイズ" は 4 バイトです。これは、ポインター
pがintを指しているためです。"バッファー サイズ" は 4096 バイトです。これは、バッファー サイズは配列のサイズに個々の配列要素型 (
int) のサイズを乗算した値 (1024 * 4 バイト) であるためです。"オフセット" は 4096 です。これは、演算
p++により、ポインターが配列を移動してバッファーの先頭から 1024*4 バイト離れたところを指しているためです。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
1 つの修正方法として、for ループ後の p の不適切なデリファレンスの削除があります。
#define Size 1024
int input(void);
void main() {
int arr[Size];
int *p = arr;
for (int index = 0; index < Size ; index++, p++) {
*p = input();
}
} typedef struct S {
int f1;
int f2;
int f3;
} S;
void Initialize(int *ptr) {
*ptr = 0;
*(ptr+1) = 0;
*(ptr+2) = 0;
}
void main(void) {
S myStruct;
Initialize(&myStruct.f1);
}この例では、Initialize の本文で、ptr は構造体の第 1 のフィールドを指す int ポインターです。ptr を通して 2 番目のフィールドへのアクセスを試みると、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 4 バイトのバッファー内でオフセット 4 にある 4 バイトを指しているため、範囲外であることが通知されます。
"ポイント先のサイズ" は 4 バイトです。これは、ポインター
ptrがintを指しているためです。"バッファー サイズ" は 4 バイトです。これは、バッファー サイズは指されている変数である
myStruct.f1の型に基づくためです。myStruct.f1の型はintです。"オフセット" は 4 です。これは、演算
(ptr + 1)により、ポインターがバッファーの先頭からintの 1 サイズ分移動されるためです。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
可能な修正の 1 つは、構造体全体へのポインターを Initialize に渡すことです。
typedef struct S {
int f1;
int f2;
int f3;
} S;
void Initialize(S* ptr) {
ptr->f1 = 0;
ptr->f2 = 0;
ptr->f3 = 0;
}
void main(void) {
S myStruct;
Initialize(&myStruct);
}#include<stdlib.h>
void main() {
int *ptr=NULL;
*ptr=0;
}この例では、ptr に値 NULL が割り当てられます。したがって、ptr をデリファレンスすると、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
ポインターが 0x0000 などの絶対アドレスで初期化される場合は、同様のエラーが表示されます。
#define RAM_START 0x0000
void main() {
int *ptr;
ptr = RAM_START;
*ptr = 0;
}[結果の詳細]:チェック メッセージで、ポインターが null であることが通知されます。ポインターが null であるため、チェックは、ポインターが割り当てられたバッファー内を指しているかどうかの検証に進みません。
1 つの修正方法として、NULL の代わりに変数のアドレスを使った ptr の初期化があります。
void main() {
int var;
int *ptr=&var;
*ptr=0;
}エラーを回避するには、解析目的のためだけに 0x0000 を別のアドレスで置き換えます。次に例を示します。
#ifdef POLYSPACE
#define RAM_START 0x0001
#else
#define RAM_START 0x0000
#endif
void main() {
int *ptr;
ptr = (int*)RAM_START;//Cast int to int*
*ptr = 0;
}-D POLYSPACE を使用して、Polyspace 解析のためにアドレス 0x0000 が代替アドレス (この例では 0x0001) に置き換えられるようにします。プリプロセッサ定義 (-D) も参照してください。この解決策は、RAM_START が有効なアドレスであることがわかっている場合にのみ使用してください。int getOffset(void);
void main() {
int *ptr = (int*) 0 + getOffset();
if(ptr != (int*)0)
*ptr = 0;
}この例では、オフセットが (int*) 0 に追加されますが、Polyspace ではその結果が有効なアドレスとして扱われません。したがって、ptr をデリファレンスすると、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインター自体は null ではないものの、メモリが割り当てられていない可能性があることが通知されます。
int arr[10];
int main(int arg, char* argv[]) {
int *ptr = &arr[10];
int val_ptr = *ptr;
return 0;
}この例では、ポインター ptr に、配列 arr に割り当てられているメモリを超えたアドレスが代入されています。ただし、この代入では [不適切にデリファレンスされたポインター] チェックはトリガーされません。このチェックは、ポインターがデリファレンスされた場合にのみ行われ、明確なエラー (レッド) を示します。
struct flagCollection {
unsigned int flag1: 1;
unsigned int flag2: 1;
unsigned int flag3: 1;
unsigned int flag4: 1;
unsigned int flag5: 1;
unsigned int flag6: 1;
unsigned int flag7: 1;
};
char getFlag(void);
int main()
{
unsigned char myFlag = getFlag();
struct flagCollection* myFlagCollection;
myFlagCollection = (struct flagCollection *) &myFlag;
if (myFlagCollection->flag1 == 1)
return 1;
return 0;
}この例では以下のようになります。
flagCollectionのフィールドはタイプがunsigned intになります。したがって、フィールドそのものの占有は 7 ビットですが、flagCollection構造体は 32 ビット アーキテクチャ内に 32 ビットのメモリを必要とします。charアドレス&myFlagをflagCollectionポインターmyFlagCollectionにキャストする場合、ポインターには 8 ビットのメモリしか割り当てられません。したがって、myFlagCollectionのデリファレンスに対し、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 1 バイトのバッファー内でオフセット 0 にある 4 バイトを指しているため、範囲外であることが通知されます。
"ポイント先のサイズ" は 4 バイトです。これは、ポインターが実質的に 1 つの
unsigned intフィールドをもつ構造体を指しているためです。すべてのビット フィールドを 1 つのunsigned int内に格納できます。"バッファー サイズ" は 1 バイトです。これは、バッファー サイズは指されている変数である
myFlagの型に基づくためです。この変数のデータ型はcharです。"オフセット" は 0 です。これは、ポインターがバッファーの先頭を指しているためです。ポインター演算は関与しません。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
1 つの修正方法として、flagCollection のフィールド タイプとして unsigned int ではなく unsigned char を使用します。この例の場合は次のようになります。
構造体
flagCollectionは 8 ビットのメモリを必要とします。charアドレス&myFlagをflagCollectionポインターmyFlagCollectionにキャストする場合、ポインターにも 8 ビットのメモリが割り当てられます。したがって、myFlagCollectionのデリファレンスに対し [不適切にデリファレンスされたポインター] チェックはグリーンになります。
struct flagCollection {
unsigned char flag1: 1;
unsigned char flag2: 1;
unsigned char flag3: 1;
unsigned char flag4: 1;
unsigned char flag5: 1;
unsigned char flag6: 1;
unsigned char flag7: 1;
};
char getFlag(void);
int main()
{
unsigned char myFlag = getFlag();
struct flagCollection* myFlagCollection;
myFlagCollection = (struct flagCollection *) &myFlag;
if (myFlagCollection->flag1 == 1)
return 1;
return 0;
}#include <stdlib.h>
void main(void)
{
char *p = (char*)malloc(1);
char *q = p;
*q = 'a';
}この例では、malloc が NULL を p に返す可能性があります。したがって、p を q に割り当てて q をデリファレンスすると、[不適切にデリファレンスされたポインター] チェックでオレンジ エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが null である可能性があることが通知されます。
malloc の戻り値を NULL についてチェック1 つの修正方法として、q のデリファレンスの前に p を NULL についてチェックします。
#include <stdlib.h>
void main(void)
{
char *p = (char*)malloc(1);
char *q = p;
if(p!=NULL) *q = 'a';
}#include <stdlib.h>
typedef struct {
int state;
union {
char myChar;
int myInt;
} myVar;
} myType;
void main() {
myType* myTypePtr;
myTypePtr = (myType*)malloc(sizeof(int) + sizeof(char));
if(myTypePtr != NULL) {
myTypePtr->state = 0;
}
}この例では以下のようになります。
共用体
myVarはint変数をフィールドとしてもつため、32 ビット アーキテクチャにおいて 4 バイトをこれに割り当てなければなりません。したがって、構造体myTypeには 4+4 = 8 バイトを割り当てる必要があります。mallocは、sizeof(int) + sizeof(char)=4+1=5 バイトのメモリをmyTypePtrに返します。これはmyType構造体を指すポインターです。したがって、myTypePtrをデリファレンスすると、[不適切にデリファレンスされたポインター] チェックはレッド エラーを返します。
[結果の詳細]:チェック メッセージで、ポインターが 5 バイトのバッファー内でオフセット 0 にある 8 バイトを指しているため、範囲外であることが通知されます。
"ポイント先のサイズ" は 8 バイトです。これは、ポインター
myTypePtrはmyType型を指しているためです。構造体myTypeには次の 2 つのフィールドがあります。intフィールド (4 バイト)。unionフィールド。共用体に含まれる最大の型はint(4 バイト) です。
"バッファー サイズ" は 5 バイトです。これは、ヒープに割り当てられたメモリのサイズが
sizeof(int) + sizeof(char)、つまり 4+1 バイトであるためです。"オフセット" は 0 です。これは、ポインターがバッファーの先頭を指しているためです。ポインター演算は関与しません。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
1 つの修正方法として、デリファレンスの前に 8 バイトのメモリを myTypePtr に割り当てるとします。
#include <stdlib.h>
typedef struct {
int state;
union {
char myChar;
int myInt;
} myVar;
} myType;
void main() {
myType* myTypePtr;
myTypePtr = (myType*)malloc(sizeof(int) * 2);
if(myTypePtr != NULL) {
myTypePtr->state = 0;
}
}#include <stdlib.h>
typedef struct {
int length;
int breadth;
} rectangle;
typedef struct {
int length;
int breadth;
int height;
} cuboid;
void main() {
cuboid *cuboidPtr = (cuboid*)malloc(sizeof(rectangle));
if(cuboidPtr!=NULL) {
cuboidPtr->length = 10;
cuboidPtr->breadth = 10;
}
}この例では、cuboidPtr はフィールドのうちの 2 つに十分対応するだけのメモリを獲得します。ANSI® C 標準ではこのような部分的なメモリ割り当ては許可されないため、cuboidPtr のデリファレンスに対し、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 8 バイトのバッファー内でオフセット 0 にある 12 バイトを指しているため、範囲外であることが通知されます。
"ポイント先のサイズ" は 12 バイトです。これは、ポインター
ptrはcuboid型を指しているためです。cuboid型には 3 つのintメンバーがあるため、そのサイズは 3 * 4 バイトとなります。"バッファー サイズ" は 8 バイトです。これは、ヒープに割り当てられたメモリのサイズは
sizeof(rectangle)と等しくなるためです。rectange型には 2 つのintメンバーがあるため、そのサイズは 2 * 4 バイトとなります。"オフセット" は 0 です。これは、ポインターがバッファーの先頭を指しているためです。ポインター演算は関与しません。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
ANSI C 規格を順守するには、cuboidPtr に完全なメモリを割り当てなければなりません。
#include <stdlib.h>
typedef struct {
int length;
int breadth;
} rectangle;
typedef struct {
int length;
int breadth;
int height;
} cuboid;
void main() {
cuboid *cuboidPtr = (cuboid*)malloc(sizeof(cuboid));
if(cuboidPtr!=NULL) {
cuboidPtr->length = 10;
cuboidPtr->breadth = 10;
}
}構造体に対して部分的にメモリを割り当て、しかも [不適切にデリファレンスされたポインター] のレッド エラーが発生しないようにできます。部分的なメモリの割り当てを可能にするには、[構成] ペインの [チェック動作] で、[構造体の不完全または部分的割り当てを許可する] を選択します。
#include <stdlib.h>
typedef struct {
int length;
int breadth;
} rectangle;
typedef struct {
int length;
int breadth;
int height;
} cuboid;
void main() {
cuboid *cuboidPtr = (cuboid*)malloc(sizeof(rectangle));
if(cuboidPtr!=NULL) {
cuboidPtr->length = 10;
cuboidPtr->breadth = 10;
}
}#include <stdlib.h>
typedef struct {
int length;
int breadth;
} square;
void main() {
square mySquare;
char* squarePtr = (char*)&mySquare.length;
//Assign zero to mySquare.length byte by byte
for(int byteIndex=1; byteIndex<=4; byteIndex++) {
*squarePtr=0;
squarePtr++;
}
//Assign zero to first byte of mySquare.breadth
*squarePtr=0;
}この例では、squarePtr は char ポインターですが、これに整数 mySquare.length のアドレスが割り当てられています。その理由は次のとおりです。
charは 1 バイトを占めます。intは 32 ビット アーキテクチャにおいて 4 バイトを占めます。
squarePtr はポインター演算を通して mySquare.length の 4 バイトにアクセスできます。ただし、別のフィールド mySquare.breadth の最初のバイトにアクセスすると、[不適切にデリファレンスされたポインター] チェックでレッド エラーが示されます。
[結果の詳細]:チェック メッセージで、ポインターが 4 バイトのバッファー内でオフセット 4 にある 1 バイトを指しているため、範囲外であることが確認されます。
"ポイント先のサイズ" は 1 バイトです。これは、ポインター
squarePtrがcharを指しているためです。"バッファー サイズ" は 4 バイトです。これは、バッファー サイズは指されている変数である
mySquare.lengthの型に基づくためです。mySquare.lengthの型はintです。"オフセット" は 4 です。これは、演算
squarePtr++を使用することで、バッファーの先頭から 1 つのintのサイズ分、ポインターが移動されているためです。
データ型のサイズはターゲットによって異なることに注意してください。この例でのサイズは、最も一般的なターゲットの場合を表しています。
1 つの修正方法として、mySquare.length ではなく、全構造体 mySquare のアドレスを squarePtr に割り当てるとします。これによって squarePtr は、ポインター演算を通して mySquare のすべてのバイトにアクセスできるようになります。
#include <stdlib.h>
typedef struct {
int length;
int breadth;
} square;
void main() {
square mySquare;
char* squarePtr = (char*)&mySquare;
//Assign zero to mySquare.length byte by byte
for(int byteIndex=1; byteIndex<=4; byteIndex++) {
*squarePtr=0;
squarePtr++;
}
//Assign zero to first byte of mySquare.breadth
*squarePtr=0;
}ポインターを使用して構造体の複数のフィールドに移動し、かつ [不適切にデリファレンスされたポインター] のレッド エラーが生じないようにできます。そのような移動を可能にするには、[構成] ペインの [チェック動作] で、[フィールド間のポインター演算を有効にする] を選択します。
このオプションは C++ プロジェクトでは使用できません。C++ では、多様型などの概念を扱う場合はポインター演算が非トリビアルになります。
#include <stdlib.h>
typedef struct {
int length;
int breadth;
} square;
void main() {
square mySquare;
char* squarePtr = (char*)&mySquare.length;
//Assign zero to mySquare.length byte by byte
for(int byteIndex=1; byteIndex<=4; byteIndex++) {
*squarePtr=0;
squarePtr++;
}
//Assign zero to first byte of mySquare.breadth
*squarePtr=0;
}void func2(int *ptr) {
*ptr = 0;
}
int* func1(void) {
int ret = 0;
return &ret ;
}
void main(void) {
int* ptr = func1() ;
func2(ptr) ;
}
次のコードで、ptr は ret を指します。ret のスコープは func1 に制限されているため、func2 内で ptr がアクセスされると、そのアクセスは無効になります。検証では、*ptr に対してレッドの [不適切にデリファレンスされたポインター] チェックが示されます。
Polyspace Code Prover™ の既定の設定では、ローカル変数にポインターを返す関数は検出されません。このような場合に検出されるようにするには、オプションスコープ外のスタック ポインター デリファレンスを検出 (-detect-pointer-escape)を使用します。
[結果の詳細]:チェック メッセージで、ポインターがスコープ外でアクセスされるローカル変数を指していることが通知されます。
#include <stdlib.h>
#include <stdio.h>
int increment_content_of_address(int base_val, int shift)
{
int j;
int* pi = (int*)malloc(sizeof(int));
if (pi == NULL) return 0;
*pi = base_val;
if(shift < 0) {
free(pi);
}
j = *pi + shift;
return j;
}この例では、引数 shift が負である場合、割り当てられたメモリが関数 free() を使用して解放された後に、ポインター pi がデリファレンスされます。[不適切にデリファレンスされたポインター] チェックは、この問題を検出して、潜在的なランタイム エラーを報告することができます (オレンジ チェック)。
この例では、ポインター ptr1 のエイリアスが条件付きで再割り当てされます。randomVar が true の場合、エイリアス ptr2 は新しい場所を指します。そうでない場合は、ptr1 と ptr2 の両方が同じ場所を指します。free ステートメントの後の ptr2 のデリファレンスでは、randomVar が false の場合に既に解放されているポインターのデリファレンスが試みられます。Polyspace は、このランタイム エラーのオレンジ チェックを報告します。
int main() {
volatile int randomVar;
int *ptr1 = (int *)malloc(sizeof(int));
void *ptr2 = (void *)ptr1;
if(randomVar) {
ptr2 = malloc(sizeof(int));
assert(ptr2 != 0);
}
free(ptr1);
*(int *)ptr2 = randomVar; // Potential IDP
}チェック情報
| グループ: 静的メモリ |
| 言語: C | C++ |
| 頭字語: IDP |
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)