メインコンテンツ

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

CWE Rule 685

Function Call With Incorrect Number of Arguments

R2023a 以降

説明

ルールの説明

The software calls a function, procedure, or routine, but the caller specifies too many arguments, or too few arguments, which may lead to undefined behavior and resultant weaknesses.

Polyspace 実装

ルール チェッカーは以下の問題をチェックします。

  • 書式文字列指定子と引数の不一致

  • 現在の引数リストに対する va_arg 呼び出しが多すぎます

  • 関数ポインターの信頼性の低いキャスト

すべて展開する

問題

この問題は、printf などの書式設定付き出力関数内の書式指定子が、それに対応する引数と一致しない場合に発生します。たとえば、unsigned long 型の引数の書式指定は %lu でなければなりません。

リスク

書式指定子と対応する引数の間の不一致により、未定義の動作が発生します。

修正方法

書式指定子が対応する引数と一致することを確認します。たとえば、次の例では、%d 指定子は文字列引数 message に一致せず、%s 指定子は整数引数 err_number に一致しません。

  const char *message = "License not available";
  int err_number = ;-4
  printf("Error: %d (error type %s)\n", message, err_number);
2 つの書式指定子を入れ替えると、問題が修正されます。書式指定子の詳細は、関数 printf の仕様を参照してください。

認識される引数のデータ型が整数プロモーションによって変更された場合、解析結果に元の型とプロモーション後の型の両方が示されます。書式指定子は整数プロモーション後の型と一致していなければなりません。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 — 浮動小数点の出力
#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%d\n", fst);  //Noncompliant
}

printf ステートメントで、書式指定子 %dfst のデータ型と一致していません。

修正 — 符号なしの long 書式指定子を使用

1 つの修正方法として、%lu 書式指定子を使用することができます。この指定子は fstunsigned 整数型および long サイズに合致します。

#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%lu\n", fst);
}
修正 — 整数引数を使用

1 つの修正方法として、書式指定子と一致するように引数を変更することができます。fst を書式指定子と一致するよう整数に変換し、値 1 を出力します。

#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%d\n", (int)fst);
}
問題

この問題は、va_arg の呼び出しの数が、対応する可変個引数関数に渡される引数の数を超えている場合に発生します。解析では、可変個引数関数が呼び出される場合にのみ欠陥が報告されます。

[現在の引数リストに対する va_arg 呼び出しが多すぎます] では、次の場合には欠陥を報告しません。

  • 可変個引数関数内の va_arg の呼び出しの数が不確定である。たとえば、呼び出しが外部ソースからのものである場合です。

  • va_arg で使用される va_list が無効である。

リスク

va_arg を呼び出すとき、va_list 内に使用可能な次の引数がないと、動作が未定義になります。va_arg の呼び出しによって、データが破損したり、予期しない結果が返されたりする可能性があります。

修正方法

適切な数の引数を可変個引数関数に渡すようにします。

例 — va_arg を呼び出すときに使用可能な引数がない
#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/
int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {
/* No further argument available 
* in va_list when calling va_arg
*/	

            result += va_arg(ap, int);  //Noncompliant
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100); 

}

この例では、func() 内で呼び出されたときに、名前付き引数と可変個引数が 1 つだけ variadic_func() に渡されます。va_arg の 2 番目の呼び出しでは、ap で使用可能な可変個引数がそれ以上ないため、動作が未定義になります。

修正 — 適切な数の引数を可変個引数関数に渡す

1 つの修正方法として、適切な数の引数を可変個引数関数に渡すようにします。

#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/

int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {

/* The correct number of arguments is
* passed to va_list when variadic_func()
* is called inside func()
*/			
            result += va_arg(ap, int); 
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100, 200); 

} 
問題

この問題は、関数ポインターが、引数または戻り値の型が異なる別の関数ポインターにキャストされた場合に発生します。

リスク

関数ポインターを引数または戻り値の型が異なる別の関数ポインターにキャストし、後者の関数ポインターを使用して関数を呼び出した場合、動作は未定義になります。

修正方法

引数または戻り値の型が一致しない 2 つの関数ポインター間のキャストは避けます。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 — 関数ポインターの信頼性の低いキャスト エラー
#include <stdio.h>
#include <math.h>
#define PI 3.142
 
double Calculate_Sum(int (*fptr)(double))
{
    double  sum = 0.0;
    double  y;
	  
    for (int i = 0;  i <= 100;  i++)
    {
        y = (*fptr)(i*PI/100);
        sum += y;
    }
    return sum / 100;
}
 
int main(void)
{
    double  (*fp)(double);      
    double  sum;
 
    fp = sin;
    sum = Calculate_Sum(fp);  //Noncompliant
    /* Defect: fp implicitly cast to int(*) (double) */

    printf("sum(sin): %f\n", sum);
    return 0;
}

関数ポインター fpdouble (*)(double) として宣言されています。しかし、関数 Calculate_Sum に渡す時に fp は暗黙的に int (*)(double) にキャストされます。

修正 — 関数ポインターのキャストを回避

1 つの修正方法として、Calculate_Sum の定義における関数ポインターが、fp と同じ引数および戻り値の型をもつことをチェックすることができます。このステップにより、fp が異なる引数または戻り値の型に暗黙的にキャストされないことが保証されます。

#include <stdio.h>
#include <math.h>
# define PI 3.142
 
/*Fix: fptr has same argument and return type everywhere*/
double Calculate_Sum(double (*fptr)(double)) 
{
    double  sum = 0.0;
    double y;
	    
    for (int i = 0;  i <= 100;  i++)
    {
        y = (*fptr)(i*PI/100);
        sum += y;
    }
    return sum / 100;
}
 
int main(void)
{
    double  (*fp)(double);      
    double  sum;
 
    
    fp = sin;
    sum = Calculate_Sum(fp);
    printf("sum(sin): %f\n", sum);
 
    return 0;
}

チェック情報

カテゴリ: その他

バージョン履歴

R2023a で導入