CERT C: Rule DCL38-C

Используйте правильный синтаксис при объявлении члена массива с переменными границами

Описание

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

Используйте правильный синтаксис при объявлении массива с переменными границами member.[1]

Реализация Polyspace

Это средство проверки проверяет на Неправильный синтаксис размера члена массива с переменными границами.

Примеры

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

Проблема

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

Начиная с C99 можно задать член массива с переменными границами с незаданным размером. Например, desc член массива с переменными границами в этом примере:

struct record {
    size_t len;
    double desc[]; 
};
До C99 вы можете использовать специфичные для компилятора методы, чтобы задать массивы с переменными границами. Например, вы использовали массивы единицы или нули размера:
struct record {
    size_t len;
    double desc[0]; 
};
Это использование несовместимо со стандартами C после C99.

Риск

Если вы задаете члены массива с переменными границами при помощи нулевого размера или один, ваша реализация зависима компилятором. Для компиляторов, которые не распознают синтаксис, int массив размера у каждого есть буфер для одного int переменная. При попытке записать вне этого буфера, можно столкнуться с проблемами, происходящими от доступа к массиву за пределы.

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

Фиксация

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

Пример - член массива с переменными границами, заданный с размером один
#include <stdlib.h>
  
struct flexArrayStruct {
  int num;
  int data[1];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<= 0 || array_size > max_size)  
      exit(1);
  /* Space is allocated for the struct */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
     malloc(sizeof(struct flexArrayStruct)
          + sizeof(int) * (array_size - 1));
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
   
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

В этом примере, член массива с переменными границами data задан со значением размера одного. Компиляторы, которые не распознают этот синтаксис, обрабатывают data как размер один массив. Оператор structP->data[i] = 1; может записать в data вне первого члена массивов и причины за пределы проблемы массивов.

Коррекция — использует стандартный синтаксис C, чтобы задать массив с переменными границами

Задайте члены массива с переменными границами с незаданным размером.

#include <stdlib.h>
  
struct flexArrayStruct{
  int num;
  int data[];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<=0 || array_size > max_size)  
      exit(1);
  
  /* Allocate space for structure */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
    malloc(sizeof(struct flexArrayStruct)
         + sizeof(int) * array_size);
         
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
 
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

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

Группа: правило 02. Объявления и инициализация (DCL)
Введенный в R2019a

[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.