メインコンテンツ

memsetmemcpy に関する Code Prover の仮定

ライブラリ関数 memset および memcpy と、これらのライブラリ関数にオプション -code-behavior-specifications を使用してマッピングされた関数には、以下の仮定が適用されます。

memcpy 向けの Polyspace 仕様

構文:

#include <string.h>
void * memcpy ( void * destinationPtr, const void * sourcePtr, size_t num );

コードが関数 memcpy を使用する場合、この表の情報を確認してください。

仕様
Polyspace® は、関数の [標準ライブラリ ルーチンの無効な使用] チェックを実行します。このチェックは、sourcePtr または destinationPtr が指すメモリ ブロックが、num を介して割り当てられたメモリ以上のサイズであるかどうかを判定します。
#include <string.h>
typedef struct {
    char a;
    int b;
 } S;

void func(int);
 
void main() {
  S s;
  int d;
  memcpy(&d, &s, sizeof(S));
}

このコードで、Polyspace は、レッドの [標準ライブラリ ルーチンの無効な使用] エラーを生成します。その理由は次のとおりです。

  • dint 変数である。

  • sizeof(S)sizeof(int) よりも大きい。

  • サイズ sizeof(S) のメモリ ブロックは &d に割り当てられている。

Polyspace は sourcePtr の未初期化のチェックをしますが、sourcePtr が指しているメモリはチェックしません。メモリが初期化されていなくても、レッドまたはオレンジの [未初期化変数] または [未初期化ローカル変数] という結果は表示されません。

memcpy の使用後、Polyspace は、destinationPtr の指す変数が型に許容される任意の値を取るとみなします。

#include <string.h>
typedef struct {
    char a;
    int b;
 } S;

void func(int);

void main() {
  S s, d={'a',1};
  int val;
  val = d.b; // val=1

  memcpy(&d, &s, sizeof(S));
  val = d.b;
  // val can have any int value
}

このコードでは、Polyspace は、関数 memcpysd にコピーするとき、レッドの [未初期化ローカル変数] エラーを生成しません。コピー後の検証では、d のフィールドがその型で許容される任意の値を取り得ると見なされます。たとえば、d.b は、int 変数に許容された範囲の任意の値を取ることができます。

ソース引数とコピー先引数が重複する場合、Polyspace はレッドの [標準ライブラリ ルーチンの無効な使用] チェックを報告します。代入の重複は、C 標準で禁止されています。

次のメモリ代入にレッド チェックが生成されます。

#include <string.h>

int main() {
  char arr[4];
  memcpy (arr, arr + 3, sizeof(int));
}

memset 向けの Polyspace 仕様

構文:

#include <string.h>
void * memset ( void * ptr, int value, size_t num );

コードが関数 memset を使用する場合、この表の情報を確認してください。

仕様
Polyspace は、関数の [標準ライブラリ ルーチンの無効な使用] チェックを実行します。このチェックは、ptr の指すメモリ ブロックが、num を介して割り当てられたメモリ以上のサイズであるかどうかを判定します。
#include <string.h>
typedef struct {
    char a;
    int b;
} S;

void main() {
 int val;
 memset(&val,0,sizeof(S));
}

このコードで、Polyspace は、レッドの [標準ライブラリ ルーチンの無効な使用] エラーを生成します。その理由は次のとおりです。

  • valint 変数である。

  • sizeof(S)sizeof(int) よりも大きい。

  • サイズ sizeof(S) のメモリ ブロックは &val に割り当てられている。

value が 0 の場合、memset の使用後に、Polyspace は ptr の指す変数が値 0 を取るとみなします。

#include <string.h>
typedef struct {
    char a;
    int b;
} S;

void main() {
 S s;
 int val;
 memset(&s,0,sizeof(S));
 val=s.b; //val=0
}

このコードで、 Polyspace は、memset の使用後に s の各フィールドが値 0 を取ると見なします。

memset の使用後、value が 0 以外の任意の値である場合、Polyspace は以下であると見なします。

  • ptr が指す変数は初期化されていないことがある。

  • 初期化されている場合、変数は型に許容される任意の値を取ることができる。

#include <string.h>
typedef struct {
    char a;
    int b;
} S;

void main() {
 S s;
 int val;
 memset(&s,1,sizeof(S));
 val=s.b;
 // val can have any int value 
}

このコードで、Polyspace は、memset の使用後に s の各フィールドが型に許容される任意の値を取ると見なします。たとえば、s.b は、int 変数に許容された範囲の任意の値を取ることができます。

memset の後では、構造体のフィールドが、構造体パックとパディング ビットによって異なる値をもつことがあります。そのため、memset による構造体フィールドの割り当ては実装によって異なります。Code Prover では、解析のこの部分が実装に依存しない方法で実行されます。解析では使用可能なすべてのパディングが許可されるため、構造体フィールドの全範囲の値が許可されます。