JPCERT コーディネーションセンター

DCL11-C. 可変引数関数に関連する型問題について理解する

DCL11-C. 可変引数関数に関連する型問題について理解する

可変引数関数の可変引数(関数宣言における ... の部分に相当する)は、va_arg() マクロによって解釈される。va_arg() マクロは、実装された可変引数関数本体のなかで、初期化された引数リストから次の引数を抽出する。抽出されるオブジェクトのサイズは指定された型により決定される。型とそれに対応する実引数が一致していない場合、動作は未定義となり、データの誤解釈やアラインメントエラーを引き起こす恐れがある(「EXP36-C. ポインタをより厳密にアラインされるポインタ型に変換しない」を参照)。

コンパイラは可変引数関数に渡される可変引数の型をチェックしない。そのため、プログラマは、実引数に既定の実引数拡張を行った後の型が、対応する仮引数の型と適合することを保証する義務がある。

違反コード (型解釈エラー)

C の printf() 関数は可変引数関数として実装されている。以下の違反コード例では、null終端バイト文字列と整数引数を、書式指定文字列の指定に反して入れ換えてしまっている。従って、整数はnull終端バイト文字列へのポインタとして解釈され、参照される。これは恐らくプログラムの異常終了を引き起こすだろう。同様に、ポインタ error_message は整数型として解釈されることに注意。

const char *error_msg = "Error occurred";
/* ... */
printf("%s:%d", 15, error_msg);
適合コード (型解釈エラー)

以下の適合コードでは、書式指定文字列を変更し、適切な変換指定子が引数に対応している。

const char *error_msg = "Error occurred";
/* ... */
printf("%d:%s", 15, error_msg);

このように、書式指定関数に渡される引数が与えられた書式指定文字列と適切に対応するよう注意しなくてはならない。

違反コード (型アラインメントエラー)

以下のコード例では、printf() 関数は間違って %d 指定子を使って long long 型整数を処理する。これにより、値が引数リストから抽出される際にデータの欠損や間違った表現につながるかもしれない。

long long a = 1;
const char msg[] = "Default message";
/* ... */
printf("%d %s", a, msg);

long long は解釈されなかったため、long long がより多くの記憶域を使用する場合、その次の書式指定子 %s が指す位置が予期せずずれてしまい、メッセージへのポインタの代わりに未知のデータが使用されることになるかもしれない。

適合コード (型アラインメントエラー)

以下の適合コードは、長さ修飾子ll%d 書式指定子に追加しており、その結果 printf() の可変引数パーサーが、可変引数リストから、long long引数に対応する正しいバイト数を抽出する。

long long a = 1;
const char msg[] = "Default message";
/* ... */
printf("%lld %s", a, msg);
違反コード (NULL)

C 標準では、NULL を整数定数またはポインタ定数のいずれか(実装定義)と定めている。NULL が可変引数を持たない関数にポインタ型実引数として渡される場合には適切な型変換が行われる。しかし、可変引数を持つ関数に可変引数として渡される場合には、例え sizeof(NULL) != sizeof(void *) だったとしても型変換は行われない。これが問題になるのは次のような状況だ:

このような状況では、次のコードは未定義の動作となる。

char* string = NULL;
printf("%s %d\n", string, 1);

int 型が 32 ビット、ポインタ型が 64 ビットのシステムでは、printf() が、2 番目の引数 NULL をポインタの上位ビット、3 番目の引数 1 をポインタの下位ビットと解釈してしまうかもしれない。この場合、printf() は、値 0x00000001 をポインタ値として使用して出力を行い、さらに %d 変換指定子に対応する値を読み取ろうとする。しかし、そこに呼出し元から提供されているものはなにもない。

適合コード (NULL)

この適合コードでは、printf()NULL を渡さないようにしている。

char* string = NULL;
printf("%s %d\n", (string ? string : "null"), 1);
リスク評価

可変引数関数に渡される引数の型と関数本体が想定する型が食い違うと、プログラムが異常終了したり、意図せぬ情報漏えいにつながる可能性がある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

DCL11-C

P6

L2

自動検出(最新の情報はこちら

ツール

バージョン

チェッカー

説明

Axivion Bauhaus Suite

6.9.0

CertC-DCL11
Compass/ROSE



現在、このレコメンデーションの違反は検出されない。可変引数関数の作成者とその呼び出し側の取り決めを強制することが困難なため、このレコメンデーションの違反を自動検出することは一般に不可能であるが、printf() 系関数へ渡される引数の型が正しいことを強制するのは比較的容易なはずである。

ECLAIR

1.2

CC2.DCL11

部分的に実装済み

GCC

4.3.5


-Wall を指定すると、書式指定出力関数に渡される引数の型が食い違う場合に警告する

Klocwork
2018

MISRA.FUNC.VARARG
SV.FMT_STR.PRINT_FORMAT_MISMATCH.BAD
SV.FMT_STR.PRINT_FORMAT_MISMATCH.UNDESIRED
SV.FMT_STR.SCAN_FORMAT_MISMATCH.BAD
SV.FMT_STR.SCAN_FORMAT_MISMATCH.UNDESIRED
SV.FMT_STR.PRINT_IMPROP_LENGTH
SV.FMT_STR.PRINT_PARAMS_WRONGNUM.FEW
SV.FMT_STR.PRINT_PARAMS_WRONGNUM.MANY
SV.FMT_STR.UNKWN_FORMAT.SCAN


LDRA tool suite
9.7.1

41 S, 589 S

部分的に実装済み

Parasoft C/C++test

10.4.1

CERT_C-DCL11-a
CERT_C-DCL11-b
CERT_C-DCL11-c
CERT_C-DCL11-d
CERT_C-DCL11-e
CERT_C-DCL11-f

There should be no mismatch between the '%s' or '%c' tag from format string and its corresponding argument in 'printf' function invocation
There should be no mismatch between the '%f' tag from format string and its corresponding argument in 'printf' function invocation
There should be no mismatch between the '%i' or '%d' tag from format string and its corresponding argument in 'printf' function invocation
There should be no mismatch between the '%u' tag from format string and its corresponding argument in 'printf' function invocation
There should be no mismatch between the '%p' tag from format string and its corresponding argument in 'printf' function invocation
There should be no difference between the number of tags from format string and the number of corresponding argument in 'printf' function invocation

Parasoft Insure++

Runtime analysis
Polyspace Bug Finder

R2018a

Format string specifiers and arguments mismatch

MISRA C:2012 Rule 17.1


String specifiers do not match corresponding arguments

The features of <stdarg.h> shall not be used

PRQA QA-C
9.5

0179 (U), 0184 (U), 0185 (U), 0186 (U), 0190 (U),

0191 (U), 0192 (U), 0193 (U), 0194 (U), 0195 (U),

0196 (U), 0197 (U), 0198 (U), 0199 (U), 0200 (U),

0201 (U), 0206 (U), 0207, 0208

部分的に実装済み
PVS-Studio

6.23

V576
関連するガイドライン
ISO/IEC TR 24772:2013 Type System [IHN]
Subprogram Signature Mismatch [OTR]
MISRA C:2012 Rule 17.1 (required)
翻訳元

これは以下のページを翻訳したものです。

DCL11-C. Understand the type issues associated with variadic functions (revision 131)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter