メインコンテンツ

CERT C++: MSC39-C

Do not call va_arg() on a va_list that has an indeterminate value

説明

ルール定義

不確定の値がある va_list に対して va_arg() を呼び出さないようにします。1

Polyspace 実装

ルール チェッカーは、"不確定な va_list 値の使用" をチェックします。

すべて展開する

問題

この問題は、以下の場合に発生します。

  • va_start または va_copy で初期化せずにローカル va_list を使用した場合。

    va_argvprintf などの関数 (可変数の引数を取る関数) でローカル va_list を使用する可能性があります。

  • va_copy を使用してコピーを作成してからそのコピーを使用する代わりに、関数パラメーターから直接 va_list (変数引数リスト) を使用した場合。

チェッカーは関数単位で動作することに注意してください。ブロック内で va_start を使用して va_list を初期化すると、チェッカーは、そのリストが関数の残りのブロックを越えて初期化されたと見なします。同様に、ブロック内で va_end を使用してリストを終了すると、チェッカーは、そのリストが関数の残りのブロックを越えて終了されたと見なします。

リスク

初期化せずにローカル va_list を使用すると、動作が未定義になります。

va_list を別の関数に渡して、そこで使用された場合は、va_list に呼び出し元の関数の不確定な値が入力されます。関数呼び出しの次の関数呼び出しで va_list を使用すると、予期せぬ結果が生じる可能性があります。

修正方法

ローカル va_list を使用する前に va_start または va_copy を使用して初期化します。

参照で va_list を渡します。呼び出し先の関数で、渡した va_list のコピーを作成し、そのコピーを使用します。そうすれば、呼び出し元関数の元の va_list へのアクセスに進むことができます。

例 – 別の関数からの va_list の直接使用
#include <cstdarg>
#include <cstdio>
#include <climits>
  
int containsOutliers(size_t count, va_list ap) {
  for (size_t i = 1; i < count; ++i) {
    if (va_arg(ap, int) > INT_MAX) { //Noncompliant
      return 1;
    }
  }
  return 0;
}
 
int printList(size_t count, ...) {
  va_list ap; 
  va_start(ap, count);
 
  if (containsOutliers(count, ap)) {
    va_end(ap);
    return 1;
  }
 
  for (size_t i = 0; i < count; ++i) {
    printf("%d", va_arg(ap, int));
  }
 
  va_end(ap);
  return 0;
}

この例では、チェッカーが、関数 containsOutliers で引数として取得された va_list 変数 ap の直接使用にフラグを設定します。

修正 – 別の関数から取得された va_list をコピーする

違反を回避するには、va_list を参照で渡して、関数 containsOutliers でその変数のコピーを作成します。コピーに対してさらなる操作を実行します。

#include <cstdarg>
#include <cstdio>
#include <climits>
  
int containsOutliers(size_t count, va_list* ap) {
  va_list copiedAp;
  va_copy (copiedAp, *ap);
  
  for (size_t i = 1; i < count; ++i) {
    if (va_arg(copiedAp, int) > INT_MAX) {
      return 1;
    }
  }
  return 0;
}
 
int printList(size_t count, ...) {
  va_list ap; 
  va_start(ap, count);
 
  if (containsOutliers(count, &ap)) {
    va_end(ap);
    return 1;
  }
 
  for (size_t i = 0; i < count; ++i) {
    printf("%d", va_arg(ap, int));
  }
 
  va_end(ap);
  return 0;
}

チェック情報

グループ: 49.その他 (MSC)

バージョン履歴

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.