ISO/IEC TS 17961 [insufmem]

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

Описание

Управляйте определением

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

Примеры

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

Описание

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

Риск

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

Фиксация

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

Смотрите примеры мер ниже.

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

Пример - динамическое выделение указателей

#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 Bug Finder.

Смотрите примеры мер ниже.

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

Пример - доступ к Указателю за пределы ошибка

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, чтобы выделить буфер, buffer size меньше, чем, чего вы требуете. Недостаточный буфер может привести к результирующим слабым местам, таким как переполнение буфера.

  • Если вы используете возвращаемое значение оператора 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 - 2013-11-15" воспроизводятся с соглашением о AFNOR. Только исходный и полный текст стандарта, как опубликовано Выпусками AFNOR - доступный через веб-сайт www.boutique.afnor.org - имеет нормативное значение.