メインコンテンツ

CERT C++: EXP58-CPP

適切な型のオブジェクトを va_start に渡す

説明

ルール定義

適切な型のオブジェクトを va_start に渡します。1

Polyspace 実装

ルール チェッカーは、"va_start に渡された不正な型のデータ" をチェックします。

すべて展開する

問題

va_start に渡された不正な型のデータは、va_start マクロの第 2 引数が以下のいずれかのデータ型である場合に発生します。

  • 既定の引数プロモーションが行われている際に変化するデータ型。

    たとえば、char および shortint または unsigned int にプロモーションされ、floatdouble にプロモーションされるとします。int 型と double 型は既定の引数プロモーションの際に変化しません。

  • (C のみ) レジスタ型または register 修飾子で宣言されているデータ型。

  • (C++ のみ) 参照データ型。

  • (C++ のみ) 非トリビアル コピー コンストラクターまたは自明でない移動コンストラクターをもつデータ型。

リスク

次のような可変個引数関数 (可変個の引数をもつ関数) を考えます。

void multipleArgumentFunction(int someArg, short rightmostFixedArg, ...) {
    va_list myList;
    va_start(myList, rightmostFixedArg);
    ...
    va_end(myList);
}
va_start マクロは、可変個引数関数の固定パラメーターの後にある追加引数をリスト内で取得できるように可変引数リストを初期化します。C11 および C++14 規格によると、フラグが設定されたいずれかのデータ型を va_start マクロの 2 番目の引数 (前の例では rightmostFixedArg) で使用する場合、動作は未定義です。

データ型が非トリビアル コピー コンストラクターに関連している場合、動作は処理系定義になります。たとえば、コピー コンストラクターが va_start の呼び出しの中で呼び出されるかどうかは、コンパイラによって異なります。

修正方法

va_start マクロを使用する際、可変個引数関数の右端の名前付きパラメーターに対して int 型、unsigned int 型、または double 型の使用を試みます。その後、このパラメーターを va_start マクロの 2 番目の引数として使用します。

たとえば、次の例では、可変個引数関数の右端の名前付きパラメーターのデータ型は、サポートされているデータ型 int です。

void multipleArgumentFunction(int someArg, int rightmostFixedArg, ...) {
    va_list myList;
    va_start(myList, rightmostFixedArg);
    ...
    va_end(myList);
}

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

例 – va_start の 2 番目の引数の不適切なデータ型
#include <string>
#include <cstdarg>

double addVariableNumberOfDoubles(double* weight, short num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num); //Noncompliant
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

double addVariableNumberOfFloats(float* weight, int num, std::string s, ...) {
    float sum=0.0;
    va_list list;
    va_start(list, s); //Noncompliant
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, float);
    }
    va_end(list);
    return sum;
}

この例で、チェッカーは以下の va_start の呼び出しにフラグを設定します。

  • addVariableNumberOfDoubles: 引数の型が short であり、この引数に対して int への既定の引数プロモーションが行われるため。

  • addVariableNumberOfFloats: 引数の型が std::string であり、非トリビアル コピー コンストラクターがあるため。

修正 — va_start の 2 番目の引数のデータ型を修正

va_start マクロの 2 番目の引数がサポートされているデータ型であることを確認します。次の例では以下の点が修正されています。

  • addVariableNumberOfDoubles で、可変個引数関数の最後の名前付きパラメーターのデータ型を int に変更。

  • addVariableNumberOfFloats で、最後の名前付きパラメーターのデータ型が int になるように、可変個引数関数の 2 番目と 3 番目のパラメーターを入れ替え。

#include <string>
#include <cstdarg>

double addVariableNumberOfDoubles(double* weight, int num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

double addVariableNumberOfFloats(double* weight, std::string s, int num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

チェック情報

グループ: 02.式 (EXP)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.