メインコンテンツ

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

CERT C: Rule EXP43-C

Avoid undefined behavior when using restrict-qualified pointers

説明

ルール定義

restrict 修飾子付きのポインターを使用する場合、未定義の動作を避けます。1

Polyspace 実装

ルール チェッカーは、"restrict 修飾子付きのポインターによるアクセスのオーバーラップ" をチェックします。

すべて展開する

問題

"restrict 修飾子付きのポインターによるアクセスのオーバーラップ" は、以下のいずれかに該当する場合に発生します。

  • 2 つの restrict 修飾子付きのポインターにより、オーバーラップするメモリ アドレスを持つオブジェクトが変更される。

  • 関数で 1 つ以上の const restrict 修飾子付きのポインターが非 const restrict 修飾子付きのポインターを変更するものの、この関数が呼び出される時点では、const および nonconst 引数は同一であるか、同じポインターから派生している。

  • オーバーラップする restrict 修飾子付きのポインターを使用して標準ライブラリ関数が呼び出される。

  • restrict 修飾子付きのポインターが、同一スコープ内の別の restrict 修飾子付きのポインターに割り当てられる。

リスク

ポインターに対する restrict 修飾子は、ブロック内では、このポインター (またはこのポインターから作成された別のポインター) だけがポイント先のオブジェクトにアクセスできることを意味します。オブジェクトを指している restrict 修飾子付きのポインターとは独立して 2 つ目のポインターを作成することはできません。

この仕様では、2 つの restrict 修飾子付きのポインターが同じオブジェクトまたはオーバーラップしているオブジェクトを指すことはできません。2 つの restrict 修飾子付きのポインターが同一メモリ アドレスまたはオブジェクトにアクセスすると、未定義の動作が発生します。

修正方法

restrict 修飾子付きのポインターを別のポインターに割り当てる場合は、割り当て先のポインター自体が restrict 修飾子付きであることを確認してください。restrict 修飾子により、コンパイラによるコード最適化が支援されます。この修飾子のインスタンスをすべて削除しても、観測可能なコードの動作は変更されません。

例 — 同一スコープ内の restrict 修飾子付きのポインター間の割り当て
int *restrict rptr1;   
int *restrict rptr2;  
int *         ptr; 
extern int arr[];

void func (void)
{
  arr[0] = 0;
  arr[1] = 1;
  rptr1 = &arr[0];
  rptr2 = &arr[1];
  rptr2 = rptr1;  //Non-compliant
  ptr   = rptr1;  //Compliant
  /* ... */

}

この例では、rptr1rptr2 が、同じ配列 arr の別々の場所を指している restrict 修飾子付きのポインターです。このような restrict 修飾子付きのポインターを同一スコープ内の別のポインターに割り当てると、ルール違反になります。

例 — restrict 修飾子付きの関数パラメーター
#include <stddef.h>
#include <stdio.h>
void addArray (size_t n, int *restrict res,
               const int *restrict lhs, const int *restrict rhs)
{
  for (size_t i = 0; i < n; ++i) {
    res[i] = lhs[i] + rhs[i];
  }
}
void foo (void)
{
  int a[100];
  memset(&a, 0, 100);
  addArray (100, a, a, a);//Noncompliant
}

この例では、3 つの restrict 修飾子付きパラメーター (lhsrhs、および res) を使用して関数 addArray() が定義されています。パラメーター lhsrhsconst restrict ポインターです。関数 addArray() の呼び出しでは、この 3 つすべてのパラメーターとして同じポインター a が使用されます。その結果、const restrict 修飾子付きのポインター lhs および rhs が、非 const restrict 修飾子付きのポインター res に関連付けられているメモリへのアクセスを試行する可能性があります。lhsres の間のアクセスのオーバーラップと、rhsres の間のアクセスのオーバーラップは、未定義の動作です。Polyspace® はこの関数呼び出し時に 2 つの違反を報告します。

例 — restrict 修飾子付きのポインターを使用したライブラリ関数の呼び出し
#include <string.h>
  
void func(void) {
  char c_str[]= "test string";
  char *ptr1 = c_str;
  char *ptr2;
 
  ptr2 = ptr1 + 3;
  /* Undefined behavior because of overlapping objects */
  memcpy(ptr2, ptr1, 6);//Noncompliant
  /* ... */
}

この例では、関数 memcpy で 2 つの restrict 修飾子付きのポインターが入力パラメーターとして指定されています。この関数は、ptr1 が指す位置からの 6 バイトを、ptr2 が指す位置にコピーします。ptr1ptr2 の間の距離が 3 バイトであるため、memcpy 関数呼び出しの結果、2 つの restrict 修飾子付きのポインターが、オーバーラップするメモリの変更を試行します。このオーバーラップするアクセスにより、未定義の動作が発生します。Polyspace はこの memcpy の呼び出しにフラグを設定します。

例 — 制限付きポインター間の割り当て
void func(void) {
  int *restrict p1;
  int *restrict p2 = p1; /* Undefined behavior */ //Noncompliant
 }

この例では、restrict 修飾子付きのポインター p1 は、同一スコープ内の別の restrict 修飾子付きのポインターに割り当てられます。このような割り当てによって未定義の動作が発生し、Polyspace はこれにフラグを設定します。この問題を解決するには、入れ子にされた別のスコープで p2 を宣言します。以下に例を示します。

void func(void) {
  int *restrict p1;
  {
      int *restrict p2 = p1;//Compliant
  }
 }

チェック情報

グループ: Rule 03.式 (EXP)

バージョン履歴

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.