CERT C: правило DCL38-C

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

Описание

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

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

Примеры

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

Описание

Неправильный синтаксис членского размера массива с переменными границами происходит, когда вы не используете стандартный Синтаксис 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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