exponenta event banner

ISO/IEC TS 17961 [insufmem]

Выделение недостаточного объема памяти

Описание

Определение правила

Недостаточно памяти. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

  • Неверный размер выделенного объекта для приведения.

  • Доступ указателя выходит за границы.

  • Неверный тип, используемый в sizeof.

  • Возможное неправильное использование sizeof.

Примеры

развернуть все

Проблема

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

Риск

Переопределение смещенного указателя имеет неопределенное поведение и может привести к аварийному завершению программы.

Зафиксировать

Предположим, что вы преобразуете указатель ptr1 кому ptr2. Если ptr1 указывает на буфер N байтов и ptr2 является type * указатель, где sizeof(type) является n байт, убедитесь, что N является целым числом, кратным n.

См. примеры исправлений ниже.

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

Пример - Динамическое распределение указателей
#include <stdlib.h>

void dyn_non_align(void){
    void *ptr = malloc(13);
    long *dest;

    dest = (long*)ptr; //defect
}

В этом примере программное обеспечение вызывает дефект при преобразовании ptr в long*. Динамически выделенная память ptr, 13 байт, не кратно размеру dest, 4 байта. Это несоответствие вызывает неправильный размер выделенного объекта для дефекта литья.

Исправление - изменение размера указателя

Одной из возможных корректировок является использование размера указателя, кратного целевому размеру. В этом примере устраните дефект, изменив выделенную память на 12 вместо 13.

#include <stdlib.h>

void dyn_non_align(void){
    void *ptr = malloc(12);
    long *dest;

    dest = (long*)ptr;
}
Пример - Статическое распределение указателей
void static_non_align(void){
    char arr[13], *ptr;
    int *dest;

    ptr = &arr[0];
    dest = (int*)ptr; //defect
}

В этом примере программное обеспечение вызывает дефект при преобразовании ptr в int* в строке 6. ptr имеет размер памяти 13 байт, поскольку массив arr имеет размер 13 байт. Размер dest 4 байта, что не кратно 13. Это несоответствие вызывает неправильный размер выделенного объекта для дефекта литья.

Исправление - изменение размера указателя

Одной из возможных корректировок является использование размера указателя, кратного целевому размеру. В этом примере устраните дефект, изменив размер массива arr кратно 4.

void static_non_align(void){
    char arr[12], *ptr;
    int *dest;

    ptr = &arr[0];
    dest = (int*)ptr;
}
Пример - Распределение с функцией
#include <stdlib.h>

void *my_alloc(int size) { 
    void *ptr_func = malloc(size); 
    if(ptr_func == NULL) exit(-1); 
    return ptr_func; 
}

void fun_non_align(void){
    int *dest1;
    char *dest2;

    dest1 = (int*)my_alloc(13);  //defect
    dest2 = (char*)my_alloc(13); //not a defect
}

В этом примере программное обеспечение вызывает дефект при преобразовании указателя, возвращенного my_alloc(13) в int* в строке 11. my_alloc(13) возвращает указатель с динамически выделенным размером 13 байт. Размер dest1 4 байта, что не является делителем 13. Это несоответствие вызывает неправильный размер выделенного объекта для дефекта литья. В строке 12 тот же вызов функции, my_alloc(13), не вызывает дефект для преобразования в dest2 из-за размера char*, 1 байт, делитель 13.

Исправление - изменение размера указателя

Одной из возможных корректировок является использование размера указателя, кратного целевому размеру. В этом примере устраните дефект, изменив аргумент для my_alloc кратно 4.

#include <stdlib.h>

void *my_alloc(int size) { 
    void *ptr_func = malloc(size); 
    if(ptr_func == NULL) exit(-1); 
    return ptr_func; 
}

void fun_non_align(void){
    int *dest1;
    char *dest2;

    dest1 = (int*)my_alloc(12); 
    dest2 = (char*)my_alloc(13); 
}
Проблема

Доступ к указателю вне границ происходит, когда указатель обнуляется за пределами его границ.

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

Риск

Переопределение указателя за пределами его границ является неопределенным поведением. Можно прочитать непредсказуемое значение или попытаться получить доступ к расположению, которое не разрешено, и обнаружить ошибку сегментации.

Зафиксировать

Исправление зависит от первопричины дефекта. Например, вы отменили ссылку на указатель внутри цикла, и произошла одна из следующих ситуаций:

  • Верхняя граница цикла слишком велика.

  • Для продвижения указателя с неправильным значением приращения указателя использовалась арифметика указателя.

Чтобы устранить проблему, необходимо изменить ограничение цикла или значение приращения указателя.

Часто детали результата показывают последовательность событий, которые привели к дефекту. Исправление может быть реализовано для любого события в последовательности. Если сведения о результатах не отображают историю событий, можно выполнить обратную трассировку, щелкнув правой кнопкой мыши параметры в исходном коде и просмотреть предыдущие связанные события. См. также раздел Интерпретация результатов поиска ошибок в интерфейсе пользователя Polyspace Desktop.

См. примеры исправлений ниже.

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

Пример - Ошибка доступа указателя за пределами границ
int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i;
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr назначается адрес arr указывает на блок памяти размера 10*sizeof(int). В for-луп, ptr увеличивается в 10 раз. В последней итерации цикла ptr точки за пределами назначенного ему блока памяти. Поэтому его нельзя обособлять.

Коррекция - Проверка того, что указатель остается в пределах границ

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

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

После последнего приращения, хотя ptr точки за пределами назначенного ему блока памяти, больше он не обособлен.

Проблема

Неправильный тип, используемый в sizeof, возникает при выполнении обоих следующих условий:

  • Адрес блока памяти назначается указателю или переносится между двумя блоками памяти. При присвоении или копировании используется sizeof оператор.

    Например, инициализация указателя выполняется с помощью malloc(sizeof(type)) или копировать данные между двумя адресами с помощью memcpy(destination_ptr, source_ptr, sizeof(type)).

  • Вы используете неверный тип в качестве аргумента sizeof оператор. Вместо типа, на который указывает указатель, используется тип указателя.

    Например, для инициализации type* указатель, вы используете malloc(sizeof(type*)) вместо malloc(sizeof(type)).

Риск

Независимо от того, что type обозначает выражение, sizeof(type*) всегда возвращает фиксированный размер. Возвращенный размер - это размер указателя на платформе в байтах. Внешний вид sizeof(type*) часто указывает на непреднамеренное использование. Эта ошибка может привести к выделению блока памяти, который намного меньше необходимого, и к таким слабым местам, как переполнение буфера.

Например, предположим, что structType - структура с десятью int переменные. При инициализации structType* указатель с помощью malloc(sizeof(structType*)) на 32-битной платформе указателю назначается блок памяти размером четыре байта. Однако должно быть полностью распределено для одного structType переменная, structType* указатель должен указывать на блок памяти sizeof(structType) = 10 * sizeof(int) байт. Требуемый размер намного больше фактического выделенного размера в четыре байта.

Зафиксировать

Инициализация type* указатель, заменить sizeof(type*) в выражении инициализации указателя с sizeof(type).

Пример - Выделение массива символов с помощью sizeof
#include <stdlib.h>

void test_case_1(void) {
    char* str;

    str = (char*)malloc(sizeof(char*) * 5);
    free(str);

}

В этом примере память выделяется для указателя символа str использование malloc из пяти стрелочных указателей. Однако str является указателем на символ, а не указателем на символ. Следовательно, sizeof аргумент, char*, неверно.

Исправление - сопоставить тип указателя с sizeof Аргумент

Одной из возможных корректировок является сопоставление аргумента с типом указателя. В этом примере: str является указателем символа, поэтому аргумент также должен быть символом.

#include <stdlib.h>

void test_case_1(void) {
    char* str;

    str = (char*)malloc(sizeof(char) * 5);
    free(str);

}
Проблема

Возможное неправильное использование sizeof происходит, когда Polyspace ® Bug Finder™ обнаруживает возможные непреднамеренные результаты использования sizeof оператор. Например:

  • Вы используете sizeof оператор для имени параметра массива, ожидающий размер массива. Однако имя параметра массива само по себе является указателем. sizeof возвращает размер этого указателя.

  • Вы используете sizeof оператор элемента массива, ожидающий размер массива. Однако оператор возвращает размер элемента массива.

  • Аргумент размера некоторых функций, таких как strncmp или wcsncpy неверно, поскольку вы использовали sizeof оператор ранее с возможно неправильными ожиданиями. Например:

    • В вызове функции strncmp(string1, string2, num), num получено от неправильного использования sizeof оператор на указателе.

    • В вызове функции wcsncpy(destination, source, num), num - это не количество широких символов, а размер в байтах, полученный с помощью sizeof оператор. Например, вы используете wcsncpy(destination, source, sizeof(destination) - 1) вместо wcsncpy(destination, source, (sizeof(desintation)/sizeof(wchar_t)) - 1).

Риск

Неправильное использование sizeof оператор может вызвать следующие проблемы:

  • Если вы ожидаете sizeof чтобы вернуть размер массива и использовать возвращаемое значение для ограничения цикла, число запусков цикла меньше ожидаемого.

  • Если используется возвращаемое значение sizeof для выделения буфера, размер буфера меньше требуемого. Недостаток буфера может привести к возникновению таких недостатков, как переполнение буфера.

  • Если используется возвращаемое значение sizeof оператор неправильно в вызове функции, функция ведет себя не так, как вы ожидаете.

Зафиксировать

Возможные исправления:

  • Не используйте sizeof оператор для имени параметра массива или элемента массива для определения размера массива.

    Рекомендуется передать размер массива в качестве отдельного параметра функции и использовать этот параметр в теле функции.

  • Используйте sizeof оператор тщательно определяет числовой аргумент функций, таких как strncmp или wcsncpy. Например, для широких строковых функций, таких как wcsncpyвместо числа байтов используйте в качестве аргумента число широких символов.

Пример - sizeof Используется неправильно для определения размера массива
#define MAX_SIZE 1024

void func(int a[MAX_SIZE]) {
    int i;

    for (i = 0; i < sizeof(a)/sizeof(int); i++)    {
        a[i] = i + 1;
    }
}

В этом примере: sizeof(a) возвращает размер указателя a а не размер массива.

Исправление - определение размера массива другим способом

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

#define MAX_SIZE 1024

void func(int a[MAX_SIZE]) {
    int i;

    for (i = 0; i < MAX_SIZE; i++)    {
        a[i] = i + 1;
    }
}

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

Разрешимость: неразрешимая
Представлен в R2019a

[1] Выдержки из стандарта «ISO/IEC TS 17961 Technical Specification - 2013-11-15» воспроизводятся с согласия AFNOR. Нормативную ценность имеет только оригинальный и полный текст стандарта, опубликованный изданиями AFNOR - доступный через веб-сайт www.boutique.afnor.org.