CERT.VA_START.TYPE

va_start() に渡される引数の型は、実装全体で、明確に定義された動作をする必要があります。具体的には、次を避けるべきです。

  • 参照
  • 配列
  • 非自明なコンストラクターまたはデストラクターを伴うクラス
  • プロトタイプのない関数への引数として、または可変個引数の関数への末尾の引数として渡されるときに、デフォルトの昇格を受けるいずれかの型

CERT.VA_START.TYPE チェッカーは、サポートされていないオブジェクト型が 2 番目の引数として va_start() に渡される場合にフラグを立てます。

脆弱性とリスク

サポートされていない型のオブジェクトを va_start() に 2 番目の引数として渡すと、未定義の動作を引き起こし、データ整合性違反を発生させる可能性があります。

軽減と防止

va_start() に渡される 2 番目の引数がサポートされている型であることを確認してください。

脆弱コード例 1

コピー
   #include <cstdarg>

   extern "C" void f(float a, ...){
     va_list list;
     va_start(list, a);
     // ...
     va_end(list);
   }

この非準拠の例では、正しくない型が 2 番目の引数として va_start() に渡されるため、Klocwork は 5 行目で CERT.VA_START.TYPE の欠陥を報告します。これは、デフォルトの引数の昇格後、型「float」が「double」に変換され、未定義の動作を引き起こす可能性があるためです。

修正コード例

コピー
   #include <cstdarg>

   extern "C" void f(double a, ...){
     va_list list;
     va_start(list, a);
     // ...
     va_end(list);
   }

脆弱なコード例 #2

コピー
    #include <cstdarg>
    #include <iostream>

    extern "C" void f(int &a, ...){
       va_list list;
       va_start(list, a);
       if (a) {
           std::cout << a << ", " << va_arg(list, int);
           a = 100; // Assign something to a for the caller
      }
      va_end(list);
   }

この非準拠の例では、参照型が 2 番目の引数として va_start() に渡され、未定義の動作を引き起こす可能性があるため、Klocwork は 6 行目で CERT.VA_START.TYPE の欠陥を報告します。

修正コード例 #2

コピー
   #include <cstdarg>
   #include <iostream>

   extern "C" void f(int *a, ...){
     va_list list;
     va_start(list, a);
     if (a && *a) {
       std::cout << a << ", " << va_arg(list, int);
       *a = 100; // Assign something to *a for the caller
     }
     va_end(list);
  }

上記のコードは、正しい型「double」が 2 番目の引数として va_start() に渡されるため、準拠しています。

脆弱なコード例 #3

コピー
    #include <cstdarg>
    #include <iostream>
    #include <string>

    extern "C" void f(std::string s, ...){
      va_list list;
      va_start(list, s);
      std::cout << s << ", " << va_arg(list, int);
      va_end(list
   }

この非準拠の例では、非自明なコピーコンストラクターが 2 番目の引数として va_start() に渡され、未定義の動作を引き起こす可能性があるため、Klocwork は 7 行目で CERT.VA_START.TYPE の欠陥を報告します。

修正コード例 #3

コピー
    #include <cstdarg>
    #include <iostream>

    extern "C" void f(const char *s, ...){
       va_list list;
       va_start(list, s);
       std::cout << (s ? s : "") << ", " << va_arg(list, int);
       va_end(list);
    }

上記のコードは、std::string の代わりに const char* を渡し、それには明確に定義された実装があるため、準拠しています。

関連チェッカー

外部参考資料