メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

標準ライブラリ ルーチンの無効な使用

無効な引数で標準ライブラリ関数が呼び出される

説明

標準ライブラリ関数の呼び出しに対するこのチェックでは、関数が有効な引数によって呼び出されているかどうかを判別します。

このチェックの動作は、メモリ ルーチン、浮動小数点ルーチン、文字列ルーチンのいずれが対象であるかによって異なります。ルーチンによって引数が無効になる状況が異なるためです。各タイプのルーチンの詳細については、以下の例を参照してください。

すべて展開する

#include <assert.h>
#include <math.h>

#define LARGE_EXP 710

enum operation {
    ASIN,
    ACOS,
    TAN,
    SQRT,
    LOG,
    EXP,
};

enum operation getOperation(void);
double getVal(void);

void main() {
    enum operation myOperation = getOperation();
    double myVal=getVal(), res;
    switch(myOperation) {
    case ASIN:
        assert( myVal <- 1.0 || myVal > 1.0);
        res = asin(myVal);
        break;
    case ACOS:
        assert( myVal < -1.0 || myVal > 1.0);
        res = acos(myVal);
        break;
    case SQRT:
        assert( myVal < 0.0);
        res = sqrt(myVal);
        break;
    case LOG:
        assert(myVal <= 0.0);
        res = log(myVal);
        break;
    case EXP:
        assert(myVal > LARGE_EXP);
        res = exp(myVal);
        break;
    }
}

この例では、各 assert ステートメントの後、Polyspace®myValassert 条件を true とする値のみが含まれているとみなします。たとえば、assert(myVal < 1.0); の後、Polyspace では myVal には 1.0 より小さい値が含まれるとみなします。

myVal が標準ライブラリ関数で引数として使用されると、その値は関数に対して無効となります。したがって、[標準ライブラリ ルーチンの無効な使用] チェックはレッド エラーを生成します。

浮動小数点ルーチンに対するこのチェックの仕様の詳細については、標準ライブラリの浮動小数点ルーチンの無効な使用を参照してください。

#include <string.h>
#include <stdio.h>

char* Copy_First_Six_Letters(void) {
  char str1[10],str2[5];
  printf("Enter string:\n");
  scanf("%s",str1);
  memcpy(str2,str1,6);
  return str2;
}

int main(void) {
  (void*)Copy_First_Six_Letters();
  return 0;
}

この例では、文字列 str2 のサイズは 5 ですが、関数 memcpy を使用して 6 文字の文字列 str1str2 にコピーされています。したがって、memcpy の呼び出しに対する [標準ライブラリ ルーチンの無効な使用] チェックはレッド エラーを生成します。

他の例については、memset と memcpy に関する Code Prover の仮定を参照してください。

修正 — 有効な引数による関数の呼び出し

1 つの修正方法として、関数 memcpy でコピーされる文字が収まるように、str2 のサイズを調整するとします。

#include <string.h>
#include <stdio.h>

char* Copy_First_Six_Letters(void) {
  char str1[10],str2[6];
  printf("Enter string:\n");
  scanf("%s",str1);
  memcpy(str2,str1,6);
  return str2;
}

int main(void) {
  (void*)Copy_First_Six_Letters();
  return 0;
}
#include <stdio.h>
#include <string.h>

char* Copy_String(void)
{
  char *res;
  char gbuffer[5],text[20]="ABCDEFGHIJKL";
  res=strcpy(gbuffer,text);
  return(res);
}

int main(void) {
  (void*)Copy_String();
}

この例では、文字列 text はサイズが gbuffer より大きくなっています。したがって、textgbuffer にコピーすると、strcpy の呼び出しに対する [標準ライブラリ ルーチンの無効な使用] チェックはレッド エラーを生成します。

修正 — 有効な引数による関数の呼び出し

1 つの修正方法として、コピー先の文字列 gbuffer をソース文字列 text 以上のサイズで宣言するとします。

#include <stdio.h>
#include <string.h>

char* Copy_String(void)
{
  char *res;
  char gbuffer[20],text[20]="ABCDEFGHIJKL";
  res=strcpy(gbuffer,text);
  return(res);
}

int main(void) {
  (void*)Copy_String();
}
#include <string>

void main() {
    std::string str = "";
    const char txt[3] = {'n','o','p'};
    str.append(txt);  //txt is not a valid string
}

この例では、txt は null で終了する文字列 (C 文字列) ではありません。したがって、std::string::append の呼び出しに対する [標準ライブラリ ルーチンの無効な使用] チェックはレッドになります。

修正 — C 文字列が想定される場合は null で終了する C 文字列を使用

const char* 引数 str を取るメソッドについては、str が NULL ではないこと、また NULL で終了する有効な C 文字列を指していることを確認します。

#include <string>

void main() {
    std::string str = "";
    const char txtStr[4] = {'n','o','p', '\0'};
    str.append(txtStr); //txtStr is valid string
}

関数 free() に対する [標準ライブラリ ルーチンの無効な使用] チェックでは、その関数のポインター引数が以下に当てはまるかどうかを判別します:

  • 非 null のポインターである。

  • malloc()realloc() などの承認済み割り当て関数によって以前に動的に割り当てられている。

このチェックは、以下のようなメモリの解放に関連する問題を検出することができます:

  • メモリの連続解放。

    #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)
            {
                j = *pi - shift;
                free(pi);
            }
    
        else if(shift > 0)
            {
                j = *pi + shift;
                free(pi);
            }
        else
            {
                j = *pi;
            }
    
        free(pi);
        return j;
    }

    この例では、ポインター pi は一部の実行パスで 2 回解放されます。[標準ライブラリ ルーチンの無効な使用] チェックでは、この問題を検出して、潜在的なランタイム エラーを報告します (オレンジ チェック)。

  • 動的に割り当てられていないメモリの解放:

    #include <stdlib.h>
    
    int performOperationsWithAllocatedMemory(unsigned int size) {
        char base = 0;
        char *ptr = &base;
        if(size > 0) {
            ptr = (char*)malloc(sizeof(char)*size);
        }
        //Some operations
        free(ptr);    
        return 0;
    }

    この例では、関数 performOperationsWithAllocatedMemory の引数 size がゼロである場合、ポインター ptr にメモリが動的に割り当てられません。しかし、引数 size がゼロである場合を含むすべてのケースで、このポインターに対して関数 free() が使用されています。[標準ライブラリ ルーチンの無効な使用] チェックでは、この問題を検出して、潜在的なランタイム エラーを報告します (オレンジ チェック)。

[標準ライブラリ ルーチンの無効な使用] チェックでは、ポインターが外部ポインターであり、その動的メモリ割り当てステータスが不明な場合に、潜在的なランタイム エラーを報告します (オレンジ チェック)。たとえば、ポインター引数をもつ関数がソース ファイルのどこでも呼び出されず、関数本体内で (最初に動的にメモリを割り当てることなく) このポインターに対して free() を使用した場合、free() に対してオレンジ チェックが表示されます。

チェック情報

グループ: Other
言語: C | C++
頭字語: STD_LIB