MISRA C++:2008 Rule 5-0-16

Операнд указателя и любой указатель, полученный из арифметики указателя, использующей этот операнд, должны оба адресовать элементы одного массива.

Описание

Определение правила

Операнд указателя и любой указатель, полученный из арифметики указателя, использующей этот операнд, должны оба адресовать элементы одного массива.

Объяснение

Это неопределенное поведение, когда результат арифметической операции указателя, которая использует указатель на элемент массива, также не указывает на:

  • Элемент массива.

  • Один из последних элементов массива. Для образца:

    int arr[3];
    int* res;
    res = arr+3; // res points to one beyond arr

Правило применяется к этим операциям. ptr является указателем на элемент массива и int_exp - целочисленное выражение.

  • ptr + int_exp

  • int_exp + ptr

  • ptr - int_exp

  • ptr + +

  • ++ ptr

  • -- ptr

  • ptr--

  • ptr [int_exp ]

Реализация Polyspace

  • Одиночные объекты, которые не являются частью массива, считаются массивами одного элемента. Например, в этом примере кода arr_one эквивалентно массиву из одного элемента. Polyspace® не помечает шаг указателя ptr_to_one потому что он указывает на один за последним элементом arr_one.

    void f_incr(int* x){
    	int* ptr_to_one = x;
        ++ptr_to_one;  // Compliant
    }
    
    void func(){
    	int arr_one=1; // Equivalent to array of one element
    	f_incr(&arr_one);
    }

  • Polyspace не помечает использование параметров указателя в арифметических операциях указателя, когда эти указатели указывают на массивы. Например, в этом фрагменте кода использование &a1[2] в f1 совместим, когда вы передаете массив в f1.

    void f1( int* const a1){
           int* b= &a1[2]; // Compliant
    }
    void f2(){
    	int arr[3] {};
    	f1(arr);	
    }

  • В структурах с несколькими элементами Polyspace не помечает результат арифметической операции указателя на элемент, который приводит к указателю, который указывает на другой элемент, если указатель указывает в выделенной памяти структуры или на один за последним элементом структуры.

    Например, в этом фрагменте кода назначение ptr_to_struct соответствует, потому что остается внутри myStruct, даже если это указывает снаружи myStruct.elem1. Использование индекса, большего, чем размерность элемента, для доступа к содержимому этого элемента не соответствует, даже если полученный адрес находится в выделенной памяти структуры.

    void func(){
    	struct {
    		char elem1[10];
    		char elem2[10];
    	} myStruct;
    	
    	char* ptr_to_struct = &myStruct.elem1[11]; //Compliant
          // Address of myStruct.elem1[11] is inside myStruct
          char val_to_struct = myStruct.elem1[11]; // Non-compliant
    }

  • В многомерных массивах Polyspace помечает любое использование индексов, которые больше, чем размерность подрешетки, для доступа к элементу этой подрешетки. Polyspace не помечает назначение адреса того же элемента подрешетки, если адрес находится внутри выделенной памяти массива верхнего уровня.

    Для примера в этом фрагменте кода назначение указателю ptr_to_arr совместим, потому что указатель указывает на адрес, который находится в выделенной памяти multi_arr. Назначение переменной arr_val не совместим, поскольку индекс, используемый для доступа к элементу подрешетки (3), больше размерности подрешетки (2).

    void func(){
    	int multi_arr[5][2];
    
          // Assigned memory is inside top level array
    	int* ptr_to_arr = &multi_arr[2][3]; //Compliant
    
    	// Use of index 3 with subarray of size 2
    	int arr_val = multi_arr[2][3]; // Non-compliant
    }

  • Polyspace помечает разыменование указателя, когда этот указатель указывает на один мимо последнего элемента массива. Например, в этом фрагменте кода назначение ptr соответствует, но дереферентство ptr не является. tab+3 один за последним элементом вкладки.

    void derefPtr(){
    	int tab[3] {};
    	int* ptr = tab+3; //Compliant
    	int res = *(tab+3); // Non-compliant
    }

Поиск и устранение проблем

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

void f_incr(int* x)
{
    int* ptr_to_one = x;
    ++ptr_to_one;  // Compliant
}

void f1(int* const a1)
{
    int* b = &a1[2]; // Compliant
}

int main()
{

    int arr_one = 1; // Equivalent to array of one element
    f_incr(&arr_one);

    int arr[3] {};
    f1(arr);

    struct {
        char elem1[10];
        char elem2[10];
    } myStruct;

    char* ptr_to_struct = &myStruct.elem1[11]; // Compliant
    ptr_to_struct = &myStruct.elem2[11]; //Non-compliant

    int tab[3] {1, 2, 3};
    int* ptr =  &tab[2];
    int res = tab[2];
    ++ptr; // Compliant
    res = *ptr; //Non-compliant

    return 0;
}

В этом примере:

  • Шаг ptr_to_one внутри f_incr() является совместимым, потому что операция приводит к появлению указателя, который указывает на один за последним элементом массива x. Целое число, которое передается в f_incr() эквивалентно массиву из одного элемента.

  • Операция с параметром указателя a1 внутри f1() совместим, потому что указатель указывает на массив arr.

  • Первое назначение ptr_to_struct соответствует, потому что elem1[11] все еще находится внутри myStruct. Второе назначение ptr_to_struct не соответствует, потому что результат операции не указывает ни на один из внутренних myStruct или одному мимо последнего элемента myStruct.

  • Шаг ptr совместим, потому что результат операции указывает на один за последним элементом tab. Беспочвенность ptr на следующей линии не соответствует.

Проверяйте информацию

Группа: Выражения
Категория: Требуемая
Введенный в R2021a