メインコンテンツ

CERT C: Rule ARR37-C

Do not add or subtract an integer to a pointer to a non-array object

説明

ルール定義

非配列オブジェクトへのポインターに対して整数を加算したり減算したりしないようにします。1

Polyspace 実装

ルール チェッカーは、次をチェックします。

  • メモリ編成の前提条件が無効です

  • クラス、構造体、または共用体のフィールドでのポインター演算

すべて展開する

問題

メモリ編成の前提条件が無効ですは、スタック内の変数のアドレスが、別の非配列変数のアドレスに対し加算または減算を行うことによって計算される場合に発生します。

リスク

スタック内の変数のアドレスが、別の変数のアドレスに対し加算または減算を行うことによって計算される場合は、特定のメモリ編成が仮定されています。仮定に誤りがある場合、計算されたアドレスへのアクセスが無効になることがあります。

修正方法

メモリ編成についての仮定に依存したアクセスは実行しないようにします。

この違反を正当化する場合は、結果またはコードにコメントを追加し、改めてレビューされないようにします。詳細は、以下を参照してください。

例 - メモリ編成への依存
void func(void) {
    int var1 = 0x00000011, var2;
    *(&var1 + 1) = 0; //Noncompliant
}

この例で、プログラマは、&var1 + 1var2 のアドレスを提供するという仮定に依存しています。したがって、[メモリ編成の前提条件が無効です]+ 演算に表示されます。さらに、[範囲外にアクセスするポインター] エラーもデリファレンスに表示されます。

修正 — メモリ編成に依存しない

1 つの修正方法として、別々に宣言された変数にアクセスする目的で、アドレスについて直接計算を実行しないようにします。

問題

"クラス、構造体、または共用体のフィールドでのポインター演算" の問題は、クラス、構造体、または共用体のフィールドに、別のフィールドのアドレスに対する加算または減算によってアクセスしようとすると発生します。フィールドが配列であり、その配列に対してポインター演算を実行する場合などは例外です。

リスク

クラス、構造体、または共用体のフィールドへのポインターでポインター演算を行うときは、メモリ内で他のフィールドが連続して並んでいると仮定します。この仮定は常に正しいわけではなく、予期しない結果や未定義の動作につながる可能性があります。

修正方法

クラス、構造体、または共用体のフィールドではポインター演算を行ないません。ポインター演算が必要な場合は、個々のフィールドではなく配列を使用するようにクラス、構造体、または共用体を再定義します。

例 — 構造体フィールドでのポインター演算
#include <stdio.h>

struct my_struct {
  int x;
  int y;
};

void print_struct(const struct my_struct* s) {
  const int* p;
  for (p = &(s->x); p <= &(s->y); p++) {     //Noncompliant
    printf("%d\n", *p);
  }
}

int main() {
  struct my_struct s = { 1, 2 };
  print_struct(&s);
  return 0;
}

この例では、関数 print_struct() が構造体 my_struct へのポインターを取っています。print_struct() は、for ループを使用して my_struct のフィールドの値を出力しようとします。

for ループは、my_structx フィールドを指すポインター const int* p を初期化し、py フィールドを指すまで p をインクリメントします。xy は配列の要素ではなく、これらに対してポインター演算を使用しているため、Polyspace はルール違反を報告します。

修正 — 配列を含むように構造体を再定義する

2 つの整数値からなる配列を含むように構造体 my_struct を再定義し、代わりにこの配列を指すポインターを使用します。

#include <stdio.h>

struct my_struct {
  int nums[2];
};

void print_struct(const struct my_struct* s) {
  const int* p;
  for (p = s->nums; p <= s->nums + 1; p++) {     //Compliant
    printf("%d\n", *p);
  }
}

int main() {
  struct my_struct s = { { 1, 2 } };
  print_struct(&s);
  return 0;
}

チェック情報

グループ: Rule 06.配列 (ARR)

バージョン履歴

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.