Незаконно разыменованный указатель

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

Описание

Это начинает работу, указатель разыменовывают, определяет, является ли указатель 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 начинает работу, разыменовывают 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 производит красную ошибку.

Исправление — Избегает, чтобы Нулевой указатель разыменовал

Одно возможное исправление должно инициализировать 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*) 0, Polyspace не обрабатывает результат как допустимый адрес. Поэтому, когда вы разыменовываете 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. Поэтому структура 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 и разыменовываете 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 начинают работу, разыменовывание 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 Использования

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

Эта опция не доступна для проектов 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++
Акроним: IDP