メインコンテンツ

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

無効なデータ型が va_arg に渡されました

可変個引数関数の引数のデータ型が va_arg 呼び出しの型と一致しない

説明

この欠陥は、va_arg 呼び出しのデータ型が、va_arg で読み取る可変個引数関数の引数のデータ型と一致しない場合に発生します。

たとえば、unsigned char 引数を可変個引数関数 func に渡します。既定の引数プロモーションにより、この引数は int にプロモートされます。unsigned char 引数を読み取る va_arg 呼び出しを使用すると、型の不一致が発生します。

void func (int n, ...) {
   ...   
   va_list args;
   va_arg(args, unsigned char);
   ...   
}

void main(void) {
   unsigned char c;
   func(1,c);
}

リスク

可変個引数関数 (可変個の引数をもつ関数) では、va_arg を使用して、可変引数リスト (va_list) から各引数を読み取ります。va_arg を使用しても、読み取る引数が実際に存在していたり、その引数のデータ型が va_arg 呼び出しのデータ型と一致することは保証されません。両方の条件が満たされていることは自分で確認する必要があります。

va_arg 呼び出しで正しくない型を読み取ると、未定義の動作が発生する可能性があります。関数の引数がスタック上に存在することが原因で、スタックの望ましくない領域にアクセスする場合があります。

修正方法

可変個引数関数に渡される引数のデータ型が、va_arg 呼び出しのデータ型と一致していることを確認します。

可変個引数関数の引数に対して既定の引数プロモーションが行われます。可変個引数関数の引数のデータ型をプロトタイプから決定することはできません。このような関数の引数では既定の引数プロモーションが実行されます (C99 規格の節 6.5.2.2 および節 7.15.1.1 を参照してください)。整数の引数に対して整数プロモーションが行われ、float 型の引数は double にプロモートされます。整数の引数では、charshort など、データ型を int で表すことができる場合、そのデータ型は int にプロモートされます。そうでない場合は unsigned int にプロモートされます。他のすべての引数ではプロモーションが行われません。

未定義の動作や処理系定義の動作を回避するには、可変個引数関数の使用を最小限にします。可変個引数関数の使用を検出するには、MISRA C:2012 Rule 17.1 または MISRA C++:2008 Rule 8-4-1 のチェッカーを使用します。

すべて展開する

#include <stdarg.h>
#include <stdio.h>

unsigned char func(size_t count, ...) {
    va_list ap;
    unsigned char result = 0;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, unsigned char);
    }
    va_end(ap);
    return result;
}

void func_caller(void) {
    unsigned char c = 0x12;
    (void)func(1, c);
}

この例では、funcunsigned char 引数を受け取ります。この引数に対して int への既定の引数プロモーションが行われます。va_arg 呼び出しのデータ型は依然として unsigned char であり、これは int 引数タイプと一致しません。

修正 — intva_arg の引数として使用

1 つの修正方法として、va_arg を使用して int 引数を読み取ります。

#include <stdarg.h>
#include <stdio.h>

unsigned char func(size_t count, ...) {
    va_list ap;
    unsigned char result = 0;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int); 
    }
    va_end(ap);
    return result;
}

void func_caller(void) {
    unsigned char c = 0x12;
    (void)func(1, c); 
}

結果情報

グループ: プログラミング
言語: C | C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: VA_ARG_INCORRECT_TYPE
影響度: Medium

バージョン履歴

R2018a で導入