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

PRE30-C. 文字列連結によってユニバーサル文字名を作成しない

PRE30-C. 文字列連結によってユニバーサル文字名を作成しない

C言語規格はユニバーサル文字名をサポートしている。識別子、文字定数、文字列リテラルにおいて、基本文字セットに含まれていない文字をユニバーサル文字名で記載できる。ユニバーサル文字名 \Unnnnnnnn は、(ISO/IEC10646 で規定されている) 8桁の識別子が nnnnnnnn である文字を示す。同様に、ユニバーサル文字名 \unnnn は、4桁の識別子が nnnn (8桁の識別子では 0000nnnn) となる文字を示す。

C言語規格 [ISO/IEC 9899:2011]、5.1.1.2 のパラグラフ 4 には次のように記載されている。

トークン連結の結果として生成される文字の並びがユニバーサル文字名の構文規則に一致する場合(6.10.3.3)、その動作は未定義である。

未定義動作3 も参照。

絶対に必要である場合を除き、一般に、識別子にユニバーサル文字名を使用するのは避けるべきである。

違反コード

以下の違反コード例では、トークンの連結によってユニバーサル文字名を生成している。

#define assign(uc1, uc2, val) uc1##uc2 = val

void func(void) {
  int \u0401;
  /* ... */
  assign(\u04, 01, 4);
  /* ... */
}
処理系固有の詳細

Microsoft Visual Studio 2013では、このコードをコンパイルし実行でき、期待通り変数に4が代入される。

Linux の GCC 4.8.1 では、このコードはコンパイルできない。コンパイラは、assign マクロの呼出しに含まれるユニバーサル文字の断片に対し、エラーメッセージ "stray '\' in program," を出力する。

適合コード

以下の適合コードではユニバーサル文字名を使用しているが、トークン連結を使って組み立ててはいない。

#define assign(ucn, val) ucn = val

void func(void) {
  int \u0401;
  /* ... */
  assign(\u0401, 4);
  /* ... */
}
リスク評価

トークンの連結によりユニバーサル文字名を生成すると、未定義の動作となる。

ルール

深刻度

可能性

修正コスト

優先度

レベル

PRE30-C

P2

L3

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

ツール

バージョン

チェッカー

説明

Axivion Bauhaus Suite

6.9.0

CertC-PRE30 実装済み
CodeSonar
5.0p0
LANG.PREPROC.PASTE
LANG.PREPROC.PASTEHASH
マクロが##演算子を使用している
#演算子に##が続く
LDRA tool suite
9.7.1

573 S

実装済み

Parasoft C/C++test

10.4.1

CERT_C-PRE30-a Avoid token concatenation that may produce universal character names

Polyspace Bug Finder

R2018a

Universal character name from token concatenation You create a universal character name by joining tokens with ## operator
PRQA QA-C

9.5

0905
PRQA QA-C++

4.3

0064, 0080
参考資料
[ISO/IEC 10646-2003]
[ISO/IEC 9899:2011] Subclause 5.1.1.2, "Translation Phases"
翻訳元

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

PRE30-C. Do not create a universal character name through concatenation (revision 120)

Top へ

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