メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C++: PRE31-C

安全でないマクロに対する引数の二次的影響を避ける

説明

ルール定義

安全でないマクロに対する引数の二次的影響を避けます。1

Polyspace 実装

ルール チェッカーは、"安全でないマクロへの引数の二次的影響" をチェックします。

すべて展開する

問題

安全でないマクロへの引数の二次的影響は、二次的影響のある式を含む安全でないマクロを呼び出すと発生します。

  • 安全でないマクロ: 展開時に、安全でないマクロは引数を複数回評価したり、まったく評価しなかったりします。

    たとえば、ABS マクロは引数 x を 2 回評価します。

    #define ABS(x) (((x) < 0) ? -(x) : (x))

  • 二次的影響: 評価されると、二次的影響のある式はその式内の 1 つ以上の変数を変更します。

    たとえば、++nn を変更しますが、n+1n を変更しません。

    チェッカーは、入れ子にされたマクロ内の二次的影響を考慮しません。また、チェッカーは関数呼び出しや volatile 変数アクセスを二次的影響と見なしません。

リスク

二次的影響のある式を含む安全でないマクロを呼び出すと、その式は複数回評価されたり、まったく評価されなかったりします。二次的影響は複数回発生する場合もあれば、一切発生しない場合もあり、予期しない動作の原因になります。

たとえば、呼び出し MACRO(++n) では、変数 n が 1 回のみインクリメントされることを想定します。MACRO が安全でないマクロの場合、インクリメントは複数回発生したり、まったく発生しなかったりします。

デバッグ モード以外では assert マクロが無効にされるため、チェッカーは、assert マクロ内の二次的影響を含む式にはフラグを設定します。デバッグ モード以外でコンパイルするには、コンパイル中に NDEBUG マクロを定義します。たとえば、GCC でフラグ -DNDEBUG を使用します。

修正方法

別のステートメントで二次的影響のある式を評価してから、その結果をマクロ引数として使用します。

たとえば、以下のようにはしません。

MACRO(++n);
次の 2 ステップで演算を実行します。
++n;
MACRO(n);
または、マクロの代わりにインライン関数を使用します。二次的影響のある式を引数としてインライン関数に渡します。

チェッカーは、マクロ本体のブロック スコープ内でのみ定義されたローカル変数の変更を二次的影響と見なします。この欠陥は、変数がマクロ本体内でのみ可視であるため発生しません。この種類の欠陥が表示された場合は、欠陥を無視します。

例 - 二次的影響のあるマクロ引数
#define ABS(x) (((x) < 0) ? -(x) : (x))
  
void func(int n) {
  /* Validate that n is within the desired range */
  int m = ABS(++n); //Noncompliant
 
  /* ... */
}

この例では、ABS マクロは引数を 2 回評価します。2 回目の評価は意図しないインクリメントになる可能性があります。

修正 — マクロの使用と式の評価を分離

1 つの修正方法として、最初にインクリメントを実行してから、その結果をマクロに渡します。

#define ABS(x) (((x) < 0) ? -(x) : (x))
  
void func(int n) {
  /* Validate that n is within the desired range */
  ++n;
  int m = ABS(n);
 
  /* ... */
}
修正 — インライン関数で式を評価

別の修正方法として、インライン関数で式を評価します。

static inline int iabs(int x) {
  return (((x) < 0) ? -(x) : (x));
}
  
void func(int n) {
  /* Validate that n is within the desired range */
 
int m = iabs(++n);
 
  /* ... */
}

チェック情報

グループ: 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.