Illegally dereferenced pointer

Указатель обозначается как внешние границы

Описание

Эта проверка вычеркивания указателя определяет, является ли указатель NULL или указывает за его пределы. Проверка происходит только тогда, когда вы высчитываете указатель, а не тогда, когда вы переназначаете другому указателю или передаете указатель на функцию.

Сообщение о проверке показывает смещение указателя и buffer size в байтах. Указатель указывает за пределы своих границ, когда сумма смещения и размер указателя превышает buffer size.

  • Буфер: Когда вы присваиваете адрес указателю, указателю выделяется блок памяти. Вы не можете получить доступ к памяти за пределами этого блока с помощью указателя. Размер этого блока - buffer size.

    Иногда, вместо определенного значения, размер может быть областью значений. Например, если вы создаете буфер динамически, используя malloc с неизвестным входом для размера, Polyspace® принимает, что размер массива может принимать полную область значений значений, разрешенных типом входных данных.

  • Смещение: Вы можете переместить указатель в пределах разрешенного блока памяти с помощью арифметики указателя. Различие между начальным местоположением указателя и его текущим местоположением является смещением.

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

Например, если указатель указывает на массив:

  • Этот buffer size является размером массива.

  • Смещение - это различие между началом массива и текущим местоположением указателя.

Примеры

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

#define Size 1024

int input(void);

void main() {
    int arr[Size];
    int *p = arr;

    for (int index = 0; index < Size ; index++, p++){
        *p = input();
    }
    *p = input();
}

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

  • Перед for цикл, p указывает на начало массива arr.

  • После for цикл, p точки вне массива.

Проверка Illegally dereferenced pointer на dereference p после for цикл вызывает красную ошибку.

Коррекция - Удаление незаконного дереференции

Одной из возможных коррекций является удаление незаконного дереферентства p после for цикл.

#define Size 1024

int input(void);

void main() {
    int arr[Size];
    int *p = arr;
 	
    for (int index = 0; index < Size ; index++, p++) {
        *p = input();
    }
}    
typedef struct S {
    int f1;
    int f2;
    int f3;
} S;

void Initialize(int *ptr) {
    *ptr = 0;
    *(ptr+1) = 0;
    *(ptr+2) = 0;
}

void main(void) {
    S myStruct;
    Initialize(&myStruct.f1);
}

В этом примере, в теле Initialize, ptr является int указатель, который указывает на первое поле структуры. Когда вы пытаетесь получить доступ ко второму полю через ptrпроверка Illegally dereferenced pointer приводит к красной ошибке.

Коррекция - Избегайте доступа к памяти вне поля структуры

Одной из возможных коррекций является передача указателя на всю структуру, чтобы Initialize.

typedef struct S {
    int f1;
    int f2;
    int f3;
} S;

void Initialize(S* ptr) {
    ptr->f1 = 0;
    ptr->f2 = 0;
    ptr->f3 = 0;
}

void main(void) {
    S myStruct;
    Initialize(&myStruct);
}
#include<stdlib.h>

void main() {
    int *ptr=NULL;
    *ptr=0;
}

В этом примере ptr присваивается значение NULL. Поэтому, когда вы высмеиваете ptrпроверка Illegally dereferenced pointer приводит к красной ошибке.

Коррекция - Избегайте разыменования указателя NULL

Одной из возможных коррекций является инициализация ptr с адресом переменной вместо NULL.

void main() {
    int var;
    int *ptr=&var;
    *ptr=0;
}
int getOffset(void);

void main() {
    int *ptr = (int*) 0 + getOffset();
    if(ptr != (int*)0)
        *ptr = 0;
}

В этом примере, хотя смещение добавлено к (int*) 0Polyspace не рассматривает результат как допустимый адрес. Поэтому, когда вы высмеиваете ptrпроверка Illegally dereferenced pointer приводит к красной ошибке.

struct flagCollection {
    unsigned int flag1: 1;
    unsigned int flag2: 1;
    unsigned int flag3: 1;
    unsigned int flag4: 1;
    unsigned int flag5: 1;
    unsigned int flag6: 1;
    unsigned int flag7: 1;
};

char getFlag(void);

int main()
{
    unsigned char myFlag = getFlag();
    struct flagCollection* myFlagCollection;
    myFlagCollection = (struct flagCollection *) &myFlag;
    if (myFlagCollection->flag1 == 1)
        return 1;
    return 0;
}

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

  • Поля flagCollection иметь тип unsigned int. Поэтому a flagCollection структура требует 32 бита памяти в 32-битной архитектуре, хотя сами поля занимают 7 бит.

  • Когда вы бросаете char адресные &myFlag в flagCollection указатель myFlagCollection, вы присваиваете только 8 битам памяти указателю. Поэтому Illegally dereferenced pointer проверка на разыменование myFlagCollection создает красную ошибку.

Коррекция - Используйте правильный тип для битовых полей

Одной из возможных коррекций является использование unsigned char как тип поля flagCollection вместо unsigned int. В этом случае:

  • Структура flagCollection требуется 8 бит памяти.

  • Когда вы бросаете char адресные &myFlag на flagCollection указатель myFlagCollection, вы также назначаете 8 бит памяти указателю. Поэтому Illegally dereferenced pointer проверка на разыменование myFlagCollection зеленый.

struct flagCollection {
    unsigned char flag1: 1;
    unsigned char flag2: 1;
    unsigned char flag3: 1;
    unsigned char flag4: 1;
    unsigned char flag5: 1;
    unsigned char flag6: 1;
    unsigned char flag7: 1;
};

char getFlag(void);

int main()
{
    unsigned char myFlag = getFlag();
    struct flagCollection* myFlagCollection;
    myFlagCollection = (struct flagCollection *) &myFlag;
    if (myFlagCollection->flag1 == 1)
        return 1;
    return 0;
}
#include <stdlib.h>

void main(void)
{
    char *p = (char*)malloc(1);
    char *q = p;
    *q = 'a';
}

В этом примере malloc может вернуться NULL на p. Поэтому, когда вы присваиваете p на q и dereference qпроверка Illegally dereferenced pointer приводит к красной ошибке.

Коррекция - Проверяйте возвращаемое значение malloc для NULL

Одной из возможных коррекций является проверка p для NULL перед дереферингом q.

#include <stdlib.h>
void main(void)
{
    char *p = (char*)malloc(1);
    char *q = p;
    if(p!=NULL) *q = 'a';
}
#include <stdlib.h>

enum typeName {CHAR,INT};

typedef struct {
    enum typeName myTypeName;
    union {
        char myChar;
        int myInt;
    } myVar;
} myType;

void main() {
    myType* myTypePtr;
    myTypePtr = (myType*)malloc(sizeof(int) + sizeof(char));
    if(myTypePtr != NULL) {
        myTypePtr->myTypeName = INT;
    }
}

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

  • Потому что объединение myVar имеет int переменная как поле, ей необходимо назначить 4 байта в 32-разрядной архитектуре. Поэтому структура myType должен быть назначен 4 + 4 = 8 байт.

  • malloc возвращает sizeof(int) + sizeof(char)= 4 + 1 = 5 байт памяти в myTypePtr, указатель на myType структура. Поэтому, когда вы ссоритесь myTypePtrпроверка Illegally dereferenced pointer возвращает красную ошибку.

Коррекция - Присвоение достаточного объема памяти указателю

Одной из возможных коррекций является назначение 8 байтов памяти myTypePtr до ссоры.

#include <stdlib.h>

enum typeName {CHAR,INT};

typedef struct {
    enum typeName myTypeName;
    union {
        char myChar;
        int myInt;
    } myVar;
} myType;

void main() {
    myType* myTypePtr;
    myTypePtr = (myType*)malloc(sizeof(int) + sizeof(int));
    if(myTypePtr != NULL) {
        myTypePtr->myTypeName = INT;
    }
}
#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} rectangle;

typedef struct {
    int length;
    int breadth;
    int height;
} cuboid;

void main() {
    cuboid *cuboidPtr = (cuboid*)malloc(sizeof(rectangle));
    if(cuboidPtr!=NULL) {
        cuboidPtr->length = 10;
        cuboidPtr->breadth = 10;
    }
}

В этом примере cuboidPtr получение достаточной памяти для размещения двух ее полей. Потому что ANSI® Стандарты C не допускают таких частичных выделений памяти, Illegally dereferenced pointer проверяют на dereference cuboidPtr создает красную ошибку.

Коррекция - Выделение полной памяти

Чтобы соблюдать стандарты ANSI C, cuboidPtr должна быть выделена полная память.

#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} rectangle;

typedef struct {
    int length;
    int breadth;
    int height;
} cuboid;

void main() {
    cuboid *cuboidPtr = (cuboid*)malloc(sizeof(cuboid));
    if(cuboidPtr!=NULL) {
        cuboidPtr->length = 10;
        cuboidPtr->breadth = 10;
    }
}
Коррекция - Используйте опцию анализа Polyspace

Вы можете разрешить частичное выделение памяти для структур, но не имеете красной Illegally dereferenced pointer ошибки. Чтобы разрешить частичное выделение памяти, на панели Configuration, в разделе Check Behavior, выберите Allow incomplete or partial allocation of structures.

#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} rectangle;

typedef struct {
    int length;
    int breadth;
    int height;
} cuboid;

void main() {
    cuboid *cuboidPtr = (cuboid*)malloc(sizeof(rectangle));
    if(cuboidPtr!=NULL) {
        cuboidPtr->length = 10;
        cuboidPtr->breadth = 10;
    }
}
#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} square;


void main() {
    square mySquare;
    char* squarePtr = (char*)&mySquare.length;
//Assign zero to mySquare.length byte by byte
    for(int byteIndex=1; byteIndex<=4; byteIndex++) {
        *squarePtr=0;
        squarePtr++;
    }
//Assign zero to first byte of mySquare.breadth
    *squarePtr=0;
}

В этом примере, хотя squarePtr является char указатель, ему присваивается адрес целого числа mySquare.length. Потому что:

  • char занимает 1 байт,

  • int занимает 4 байта в 32-битной архитектуре,

squarePtr может получить доступ к четырем байтам mySquare.length через арифметику указателя. Но когда он обращается к первому байту другого поля mySquare.breadthпроверка Illegally dereferenced pointer приводит к красной ошибке.

Коррекция - Присвоение адреса структуры вместо поля

Одной из возможных коррекций является назначение squarePtr адрес полной структуры mySquare вместо mySquare.length. squarePtr может затем получить доступ ко всем байтам mySquare через арифметику указателя.

#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} square;


void main() {
    square mySquare;
    char* squarePtr = (char*)&mySquare;
//Assign zero to mySquare.length byte by byte
    for(int byteIndex=1; byteIndex<=4; byteIndex++) {
        *squarePtr=0;
        squarePtr++;
    }
//Assign zero to first byte of mySquare.breadth
    *squarePtr=0;
}
Коррекция - Используйте опцию анализа Polyspace (не доступна на C++)

Можно использовать указатель для навигации по полям структуры и не создавать ошибку красного Illegally dereferenced pointer. Чтобы разрешить такую навигацию, на панели Configuration, под Check Behavior, выберите Enable pointer arithmetic across fields.

Эта опция недоступна для проектов C++. В C++ арифметика указателя становится нетривиальной при работе с концепциями, как полиморфные типы.


#include <stdlib.h>
typedef struct {
    int length;
    int breadth;
} square;


void main() {
    square mySquare;
    char* squarePtr = (char*)&mySquare.length;
//Assign zero to mySquare.length byte by byte
    for(int byteIndex=1; byteIndex<=4; byteIndex++) {
        *squarePtr=0;
        squarePtr++;
    }
//Assign zero to first byte of mySquare.breadth
    *squarePtr=0;
}
void func2(int *ptr) {
    *ptr = 0; 
}

int* func1(void) {
    int ret = 0;
    return &ret ;
}
void main(void) {
    int* ptr = func1() ;
    func2(ptr) ;
}

В следующем коде ptr точки на ret. Потому что возможности ret ограничивается func1, когда ptr доступ осуществляется в func2, доступ запрещен. Эта верификация производит проверку Illegally dereferenced pointer красным цветом *ptr.

По умолчанию Polyspace Code Prover™ не обнаруживает функции, возвращающие указатели на локальные переменные. Чтобы обнаружить такие случаи, используйте опцию Detect stack pointer dereference outside scope (-detect-pointer-escape).

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

Группа: Статическая память
Язык: C | C++
Акроним: ВПЛ