Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top

Вебинар: Использование статических анализаторов кода при разработке безопасного ПО - 19.12

>
>
>
V6050. Class initialization cycle is pr…
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Микрооптимизации (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C++)
Стандарт OWASP (C#)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V6050. Class initialization cycle is present.

01 Июн 2018

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

Случай 1.

Использование статического поля до того, как оно будет проинициализировано.

Рассмотрим синтетический пример некорректного кода:

public class Purse
{
  static private Purse reserve = new Purse(10);
  static private int scale = 5 + (int) (Math.random() * 5);

  private int deposit;

  Purse() {
    deposit = 0;
  }
  
  Purse(int initial) {
    deposit = initial * scale;
  }
  ...
}

Как известно, статические поля будут инициализироваться в порядке объявления самыми первыми при первом использовании класса. Следовательно, в данном примере сначала инициализируется 'reserve', а потом 'scale'.

Рассмотрим инициализацию статического поля 'reserve':

  • Вызывается конструктор 'Purse' с аргументом 'initial = 10'.
  • На момент выполнения выражения 'initial * scale' в вызываемом конструкторе, поле 'scale' еще не инициализировано, и будет равно значению по умолчанию (0), вместо значения из диапазона [5;10].

Вследствие чего, поле 'deposit' у объекта 'reserve' будет проинициализировано не так, как задумывалось.

Для того, чтобы исправить ситуацию, необходимо поменять порядок объявления статических полей:

public class Purse
{
  static private int scale = 5 + (int) (Math.random() * 5);
  static private Purse reserve = new Purse(10);
  
  private int deposit;

  Purse() {
    deposit = 0;
  }
  
  Purse(int initial) {
    deposit = initial * scale;
  }
  ...
}

Случай 2.

Взаимная зависимость статических полей разных классов.

Рассмотрим синтетический пример некорректного кода:

public class A {
  public static int scheduleWeeks = B.scheduleDays / 7 + 1;
  ....
}
....
public class B {
  public static int scheduleDays = A.scheduleWeeks * 7 + 7;
  ....
}

Ситуация здесь такова, что статическое поле 'A.scheduleWeeks' зависит от статического поля 'B.scheduleDays', и наоборот. Порядок инициализации классов может меняться, отсюда меняется и порядок инициализации статических полей. Если инициализируется первым класс 'A', то 'A.scheduleWeeks' будет иметь значение 2, а 'B.scheduleDays' – 7. Если первым будет класс 'B', то 'A.scheduleWeeks' будет равен 1, а 'B.scheduleDays' – 14. Вряд ли такое поведение будет приятно наблюдать у себя в коде. В таком случае необходимо пересмотреть инициализацию этих полей и убрать зависимость друг от друга.

Например, можно одно из статических полей инициализировать константой, и эта зависимость исчезнет:

public class A {
  public static int scheduleWeeks = B.scheduleDays / 7 + 1;
  ....
}
....
public class B {
  public static int scheduleDays = 14;
  ....
}

В таком случае 'B.scheduleDays' всегда будет равен 14, а 'A.scheduleWeeks' – 3.

Случай 3.

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

Рассмотрим синтетический пример некорректного кода:

public class A {
  public static int scheduleWeeks = B.getScheduleWeeks();
  public static int getScheduleDays() { return 21; }
  ....
}
....
public class B {
  public static int getScheduleWeeks() {return A.getScheduleDays()/7;}
  ....
}

Независимо от того, какой из классов первым будет инициализирован, поле 'A.scheduleWeeks' примет значение равное 3. Несмотря на это, такой способ инициализации сбивает с толку при чтении и поддержке такого кода.

Например, можно подкорректировать код следующим образом:

public class A {
  public static int scheduleWeeks = B.getScheduleWeeks();
  
  ....
}
....
public class B {
  public static int getScheduleDays() { return 21; }
  public static int getScheduleWeeks() {return B.getScheduleDays()/7;}
}

Данная диагностика классифицируется как:

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V6050.

close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам