exponenta event banner

CERT C++: DCL30-C

Объявление объектов с соответствующими сроками хранения

Описание

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

Объявление объектов с соответствующими сроками хранения. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие указателя или ссылки на переменную стека, покидающую область.

Примеры

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

Проблема

Указатель или ссылка на переменную стека, покидающую область, возникает, когда указатель или ссылка на локальную переменную выходит из области действия переменной. Например:

  • Функция возвращает указатель на локальную переменную.

  • Назначение выполняется функцией globPtr = &locVar. globPtr является глобальной переменной указателя и locVar является локальной переменной.

  • Назначение выполняется функцией *paramPtr = &locVar. paramPtr является параметром функции, который является, например, int** указатель и locVar является локальным int переменная.

  • Метод C++ выполняет назначение memPtr = &locVar. memPtr является элементом данных указателя класса, которому принадлежит метод. locVar является переменной, локальной для метода.

Дефект также относится к памяти, выделенной с помощью alloca функция. Дефект не относится к статическим локальным переменным.

Риск

Локальным переменным назначается адрес в стеке. После окончания области действия локальной переменной этот адрес становится доступным для повторного использования. Использование этого адреса для доступа к значению локальной переменной вне области действия переменной может привести к непредвиденному поведению.

Если указатель на локальную переменную выходит из области действия переменной, Polyspace ® Bug Finder™ выделяет дефект. Дефект появляется, даже если адрес, сохраненный в указателе, не используется. Для поддерживаемого кода рекомендуется не разрешать указателю выходить из области действия переменной. Даже если вы сейчас не используете адрес в указателе, кто-то другой, использующий вашу функцию, может использовать адрес, вызывая неопределенное поведение.

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

Не допускайте выхода указателя или ссылки на локальную переменную из области действия переменной.

Пример - Указатель на локальную переменную, возвращаемую функцией
void func2(int *ptr) {
    *ptr = 0;
}

int* func1(void) {
    int ret = 0;
    return &ret ;
}
void main(void) {
    int* ptr = func1() ;
    func2(ptr) ;
}

В этом примере: func1 возвращает указатель на локальную переменную ret.

В main, ptr указывает на адрес локальной переменной. Когда ptr доступен в func2, доступ запрещен, поскольку область действия ret ограничивается func1,

Пример - Указатель на локальную переменную через лямбда-выражение
auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [&] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

В этом примере createAdder функция определяет лямбда-выражение adder который захватывает локальную переменную addThis по ссылке. Объем addThis ограничивается createAdder функция. Когда объект возвращен createAdder вызывается, ссылка на переменную addThis доступен за пределами его области действия. При обращении таким образом значение addThis не определен.

Исправление - захват локальных переменных копированием в лямбда-выражении вместо ссылки

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

Переменные, захваченные копией, имеют тот же срок службы, что и лямбда-объект, но переменные, захваченные ссылкой, часто имеют меньший срок службы, чем сам лямбда-объект. При использовании лямбда-объекта эти переменные, доступные вне области действия, имеют неопределенные значения.

auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [=] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

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

Группа: 01. Объявления и инициализация (DCL)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.