Main Content

CWE Rule 843

Access of Resource Using Incompatible Type ('Type Confusion')

Since R2023a

Description

Rule Description

The program allocates or initializes a resource such as a pointer, object, or variable using one type, but it later accesses that resource using a type that is incompatible with the original type.

Polyspace Implementation

The rule checker checks for these issues:

  • Cast to pointer pointing to object of different type

  • Reading memory reallocated from object of another type without reinitializing first

Examples

expand all

Issue

The issue occurs when you perform a cast between a pointer to an object type and a pointer to a different object type.

Risk

If a pointer to an object is cast into a pointer to a different object, the resulting pointer can be incorrectly aligned. The incorrect alignment causes undefined behavior.

Even if the conversion produces a pointer that is correctly aligned, the behavior can be undefined if the pointer is used to access an object.

Exception: You can convert a pointer to object type into a pointer to one of these types:

  • char

  • signed char

  • unsigned char

Example - Cast to Pointer Pointing to Object of Wider Type
signed   char *p1;
unsigned int *p2;

void foo(void){ 
  p2 = ( unsigned int * ) p1;     /* Non-compliant */				
}

In this example, p1 can point to a signed char object. However, p1 is cast to a pointer that points to an object of wider type, unsigned int.

Example - Cast to Pointer Pointing to Object of Narrower Type
extern unsigned int read_value ( void );
extern void display ( unsigned int n );

void foo ( void ){
  unsigned int u = read_value ( );
  unsigned short *hi_p = ( unsigned short * ) &u;    /* Non-compliant  */	
  *hi_p = 0;                                         
  display ( u );                                     
}

In this example, u is an unsigned int variable. &u is cast to a pointer that points to an object of narrower type, unsigned short.

On a big-endian machine, the statement *hi_p = 0 attempts to clear the high bits of the memory location that &u points to. But, from the result of display(u), you might find that the high bits have not been cleared.

Example - Cast Adding a Type Qualifier
const short *p;
const volatile short *q;
void foo (void){
  q = ( const volatile short * ) p;  /* Compliant */								
}

In this example, both p and q can point to short objects. The cast between them adds a volatile qualifier only and is therefore compliant.

Issue

This issue occurs when you do the following in sequence:

  1. Reallocate memory to an object with a type that is different from the original allocation.

    For instance, in this code snippet, a memory originally allocated to a pointer with type struct A* is reallocated to a pointer with type struct B*:

    struct A;
    struct B;
    
    struct A *Aptr = (struct A*) malloc(sizeof(struct A));
    struct B *Bptr = (struct B*) realloc(Aptr, sizeof(struct B));

  2. Read from this reallocated memory without reinitializing the memory first.

    Read accesses on the pointer to the reallocated memory can happen through pointer dereference or array indexing. Passing the pointer to a function that takes a pointer to a const-qualified object as the corresponding parameter also counts as a read access.

Risk

Reading from reallocated memory that has not been reinitialized leads to undefined behavior.

Fix

Reinitialize memory after reallocation and before the first read access.

The checker considers any write access on the pointer to the reallocated memory as satisfying the reinitialization requirement (even if the object might only be partially reinitialized). Write accesses on the pointer to the reallocated memory can happen through pointer dereference or array indexing. Passing the pointer to a function that takes a pointer to a non-const-qualified object as the corresponding parameter also counts as a write access.

Example – Noncompliant: Reading from Reallocated Memory Without Reinitializing First
#include<stdlib.h>

struct group {
    char *groupFirst;
    int groupSize;
};

struct groupWithID {
    int groupID;
    char *groupFirst;
    int groupSize;
};

char* readName();
int readSize();

void createGroup(int nextAvailableID) {
    struct group *aGroup;
    struct groupWithID *aGroupWithID;
    
    aGroup = (struct group*) malloc(sizeof(struct group));
    
    if(!aGroup) {
        /*Handle error*/
    }
    
    aGroup->groupFirst = readName();
    aGroup->groupSize  = readSize();
    
    /* Reassign to group with ID */
    aGroupWithID = (struct groupWithID*) realloc(aGroup, sizeof(struct groupWithID));
    if(!aGroupWithID) {
        free(aGroup);
        /*Handle error*/
    }
    
    if(aGroupWithID -> groupSize > 0) { /* Noncompliant */
        /* ... */
    }
    
    /* ...*/
    free(aGroupWithID);
}

In this example, the memory allocated to a group* pointer using the malloc function is reallocated to a groupWithID* pointer using the realloc function. There is a read access on the reallocated memory before the memory is reinitialized.

Correction – Reinitialize Memory After Reallocation and Before First Read

Reinitialize the memory assigned to the groupWithID* pointer before the first read access. All bits of the memory can be reinitialized using the memset function.

#include<stdlib.h>
#include<string.h>

struct group {
    char *groupFirst;
    int groupSize;
};

struct groupWithID {
    int groupID;
    char *groupFirst;
    int groupSize;
};

char* readName();
int readSize();

void createGroup(int nextAvailableID) {
    struct group *aGroup;
    struct groupWithID *aGroupWithID;
    
    aGroup = (struct group*) malloc(sizeof(struct group));
    
    if(!aGroup) {
        /*Handle error*/
    }
    
    aGroup->groupFirst = readName();
    aGroup->groupSize  = readSize();
    
    /* Reassign to group with ID */
    aGroupWithID = (struct groupWithID*) realloc(aGroup, sizeof(struct groupWithID));
    if(!aGroupWithID) {
        free(aGroup);
        /*Handle error*/
    }
    
    memset(aGroupWithID, 0 , sizeof(struct groupWithID));
    /* Reinitialize group */
    if(aGroupWithID -> groupSize > 0) { 
        /* ... */
    }
    
    /* ...*/
    free(aGroupWithID);
}

Check Information

Category: Type Errors

Version History

Introduced in R2023a

expand all