Main Content

CERT C++: EXP39-C

Do not access a variable through a pointer of an incompatible type

Description

Rule Definition

Do not access a variable through a pointer of an incompatible type.1

Polyspace Implementation

The rule checker checks for these issues:

  • Pointer conversion to unrelated pointer type

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

.

Examples

expand all

Issue

This issue occurs when you convert a pointer to an unrelated pointer type. The checker flags all pointer conversions including between a pointer to a struct object and a pointer to the first member of the same struct type. Indirect conversions from a pointer to non-pointer type are not detected.

Risk

The outcome of the conversion between pointers of unrelated types is unspecified in the C standard. Such conversion might result in unexpected behavior.

Fix

Avoid converting pointers to unrelated types. Refactor your code and logic to reduce the necessity of pointer conversions.

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 is 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<cstdlib>

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));
    aGroup->groupFirst = readName();
    aGroup->groupSize  = readSize();
    
    if(!aGroup) {
        /*Handle error*/
    }
    
    /* 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<cstdlib>
#include<cstring>

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));
    aGroup->groupFirst = readName();
    aGroup->groupSize  = readSize();
    
    if(!aGroup) {
        /*Handle error*/
    }
    
    /* 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

Group: 02. Expressions (EXP)

Version History

Introduced in 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.