exponenta event banner

Указатель или ссылка на переменную стека, покидающую область

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

Описание

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

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

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

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

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

  • (C++ 11 и более поздние версии) Функция возвращает объект лямбда-выражения, который захватывает локальные переменные функции по ссылке.

Дефект также относится к памяти, выделенной с помощью 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);
}

Информация о результатах

Группа: Статическая память
Язык: C | C++
По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода
Синтаксис командной строки: LOCAL_ADDR_ESCAPE
Воздействие: Высокое
CWE ID: 562, 825
Представлен в R2015b