Main Content

MISRA C:2023 Rule 18.1

A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand

Since R2024a

Description

Rule Definition

A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand.

Rationale

Using an invalid array subscript can lead to erroneous behavior of the program. Run-time derived array subscripts are especially troublesome because they cannot be easily checked by manual review or static analysis.

The C Standard defines the creation of a pointer to one beyond the end of the array. The rule permits the C Standard. Dereferencing a pointer to one beyond the end of an array causes undefined behavior and is noncompliant.

If you convert a T* pointer to a char* or unsigned char* pointer, the bound of the converted pointer is considered sizeof(T). For instance, in this code, array accommodates 4 objects of type unsigned char.

unsigned int obj = 42;
unsigned char *array = (unsigned char*) &obj;
unsigned char small_obj = array[3];

Polyspace Implementation

  • Single objects that are not part of an array are considered arrays of one element. For instance, in this code example, arr_one is equivalent to an array of one element. Polyspace® does not flag the increment of pointer ptr_to_one because it points to one past the last element of 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 does not flag the use of pointer parameters in pointer arithmetic operations when those pointers point to arrays. For instance, in this code snippet, the use of &a1[2] in f1 is compliant when you pass an array to f1.

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

  • In structures with multiple elements, Polyspace does not flag the result of a pointer arithmetic operation on an element that results in a pointer that points to a different element if the pointer points within the allocated memory of the structure or to one past the last element of the structure.

    For instance, in this code snippet, the assignment to ptr_to_struct is compliant because it remains inside myStruct, even if it points outside myStruct.elem1. Using an index larger than the element dimension to access the content of that element is not compliant, even if the resulting address is within the allocated memory of the structure.

    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
    }

  • In multidimensional arrays, Polyspace flags any use of indices that are larger than a subarray dimension to access an element of that subarray. Polyspace does not flag the assignment of the address of that same subarray element if the address is inside the allocated memory of the top-level array.

    For example, in this code snippet, the assignment to pointer ptr_to_arr is compliant because the pointer points to an address that is within the allocated memory of multi_arr. The assignment to variable arr_val is not compliant because the index used to access the subarray element (3) is larger than the dimension of the subarray (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 flags the dereference of a pointer when that pointer points to one past the last element of an array. For instance, in this code snippet, the assignment of ptr is compliant, but the dereference of ptr is not. tab+3 is one past the last element of tab.

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

  • Polyspace does not raise this checker when the result of a pointer arithmetic operation results in nullptr. For instance, consider this code:

    void g(int *p);
    
    void add(int* p, int n) {
        g(p + n);   //Compliant}
    
    void foo() {
        add(nullptr, 0);
        
    }
    The pointer arithmetic in add() results in a nullptr. Polyspace does not flag this operation.

Extend Checker

A default Bug Finder analysis might not raise a violation of this rule when the input values are unknown and only a subset of inputs can cause an issue. To check for violations caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Troubleshooting

If you expect a rule violation but do not see it, refer to Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

IN this example, the pointer pointer initially points to one element beyond the end of the buffer array. Pointing to one beyond the end is allowed in the C standard, but dereferencing this location causes undefined behavior and is noncompliant with this rule. Polyspace reports violations when the code dereferences *pointer and *(pointer++).

void foo ( void )
{
  int array[10] = {0};
  int* pointer = &array[10];
  int data1 = *(pointer++); /* Noncompliant*/ 
  int data2 = *(pointer); /* Noncompliant*/
  int data3 = *(pointer--); /* Compliant*/

}

Check Information

Group: Pointers and Arrays
Category: Required
AGC Category: Required

Version History

Introduced in R2024a