ISO/IEC TS 17961 [insufmem]

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

Описание

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

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

Реализация Polyspace

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

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

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

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

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

Примеры

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

Проблема

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

Риск

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

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

Предположим, вы преобразуете указатель мыши ptr1 на ptr2. Если ptr1 указывает на буфер N байты и ptr2 является type * указатель, где sizeof (type) является n bytes, убедитесь, что 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); 
}
Проблема

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

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

Риск

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

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

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

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

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

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

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

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

Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты 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).

Пример - Выделение массива Char с sizeof
#include <stdlib.h>

void test_case_1(void) {
    char* str;

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

}

В этом примере память выделяется для символьного указателя str использование malloc из пяти указателей char. Однако 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 оператор для имени параметра массива, ожидающий размера массива. Однако имя параметра массива само по себе является указателем. The 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;
    }
}

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

Решимость: Undecidable
Введенный в R2019a

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