# V1036. Potentially unsafe double-checked locking.

Анализатор обнаружил потенциальную ошибку, связанную с небезопасным использованием паттерна "блокировки с двойной проверкой" (double checked locking). Блокировка с двойной проверкой - это паттерн, предназначенный для уменьшения накладных расходов получения блокировки. Сначала проверяется условие блокировки без синхронизации. И только если условие выполняется, поток попытается получить блокировку. Таким образом, блокировка будет выполнена только если она действительно была необходима.

Рассмотрим пример с ошибкой:

    static std::mutex mtx;
    class TestClass
    {
    public:
      void Initialize()
      {
        if (!initialized)
        {
          std::lock_guard lock(mtx);
          if (!initialized) // <=
          {
            resource = new SomeType();
            initialized = true;
          }
        }
      }
      /* .... */

      private:
        bool initialized = false;
        SomeType *resource = nullptr;
      };
    }

В этом примере, оптимизация компилятором порядка назначений переменных 'resource' и 'initialized' может привести к ошибке. Т.е. в начале переменной 'initialized' будет присвоено значение 'true', а уже потом будет выделена память под объект типа 'SomeType' и проинициализирована переменная 'resource'.

Такая перестановка может привести к ошибке при доступе к объекту из параллельного потока. Получается, что переменная 'resource' будет еще не проинициализирована, а флаг 'intialized' уже будет выставлен в 'true'.

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

Дополнительные ссылки:

- Scott Meyers and Andrei Alexandrescu. C++ and the Perils of Double-Checked Locking.
- Stack Overflow. What the correct way when use Double-Checked Locking with memory barrier in c++?
- Double-Checked Locking is Fixed In C++11.

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки при работе с многопоточными примитивами (интерфейсами запуска потоков на выполнение, синхронизации и обмена данными между потоками и пр.).

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

CWE-609

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