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 - имеет нормативное значение.