Статический анализ в видеоигровой индустрии: топ-10 программных ошибок


    Если вы занимаетесь разработкой ПО в сфере видеоигровой индустрии и задаётесь вопросом о том, что ещё можно сделать, чтобы повысить качество продукта \ упростить процесс разработки, и при этом не используете статический анализ — самое время начать. Сомневаетесь? Что ж, я попробую вас в этом убедить. Если же вам просто интересно посмотреть на ошибки, которые допускают разработчики из сферы видеоигровой индустрии, то, опять же, вы попали по адресу — специально для вас отобраны наиболее интересные.

    Почему вам следует использовать статический анализ


    Несмотря на то, что разработка видеоигр включает в себя большое количество этапов, одним из основных остаётся программирование. Даже если вы не пишете тысячи строк кода, так или иначе приходится использовать различные инструменты, от качества которых зависят в том числе удобство работы и конечный результат. Если же вы являетесь разработчиком таких инструментов (например, игровых движков), вам и так должно быть всё понятно.

    Почему статический анализ полезен в сфере разработки программного обеспечения в целом?

    Есть несколько основных причин:

    • Стоимость и сложность исправления ошибки возрастает со временем. Одно из основных преимуществ статического анализа — обнаружение ошибок на ранних этапах разработки (можно находить ошибку в момент написания кода). Следовательно, используя статический анализатор, можно упростить жизнь себе и коллегам, обнаруживая и исправляя многие ошибки до того, как они станут причиной головной боли.
    • С помощью статического анализа можно выявлять множество различных паттернов ошибок (copy-paste, опечатки, неправильное использование функций и т.д.).
    • Как правило, статический анализ хорош в выявлении тех проблем, которые плохо выявляются с помощью динамического анализа. Впрочем, справедливо и обратное утверждение.
    • Негативные моменты использования (например, ложные срабатывания), как правило, 'сглаживаются' командами-разработчиками серьёзных статических анализаторов за счёт различных функций подавления предупреждений (единичное, по паттерну и т.п.), отключения неактуальных диагностик, исключения из анализа файлов и директорий. Благодаря этому можно значительно уменьшить процент 'шума', правильно настроив анализатор. Мой коллега Андрей Карпов продемонстрировал в статье про проверку EFL Core Libraries, что в случае настройки анализатора количество ложных срабатываний составит всего 10-15%.

    Но так или иначе, это всё теория, а вам, наверняка, интересны более практические примеры. Что же, они представлены ниже.

    Статический анализ в Unreal Engine



    Если вы дочитали до этого момента, что-то рассказывать вам о том, что такое Unreal Engine или что за компания такая — Epic Games — не стоит, и, если эти ребята не пользуются у вас авторитетом — напишите мне, кто тогда пользуется.

    Команда PVS-Studio несколько раз сотрудничала с командой Epic Games, помогая им внедрять и использовать статический анализ в проекте Unreal Engine и исправлять ошибки \ ложные срабатывания, обнаруженные анализатором. Уверен, это был интересный и полезный опыт для обеих сторон.

    Одним из следствий стало добавление в Unreal Engine специального флага, который позволил удобно интегрировать статический анализ в сборочную систему Unreal Engine проектов.

    Ключевая мысль проста — ребята заботятся о качестве своего кода и используют для этого разные подходы, одним из которых стало внедрение статического анализа.

    Джон Кармак о статическом анализе



    Джон Кармак, один из самых известных разработчиков в сфере видеоигровой индустрии, в своё время признал активное использование методики статического анализа одним из главных своих достижений как программиста: "The most important thing I have done as a programmer in recent years is to aggressively pursue static code analysis." В следующий раз, когда кто-то из ваших знакомых скажет, что статический анализ – инструмент для новичков, покажите ему эту цитату. Своё знакомство со статическим анализом Кармак описал в соответствующей статье, с которой я настоятельно рекомендую ознакомиться: как для мотивации, так и для общего развития.

    Ошибки, найденные с помощью статического анализа в играх и игровых движках



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

    В выигрыше остаются все:

    • Разработчики проектов получают уведомления об ошибках и могут их поправить. В идеале, конечно, подход должен быть иным, нежели исправление ошибок по логу \ статье – стоит самостоятельно проверить анализатором проект и изучить выданные предупреждения. Это важно хотя бы по той причине, что авторы статей могут что-то упускать из виду или непреднамеренно делать акцент на тех ошибках, которые не критичны для проекта.
    • Разработчики анализатора могут улучшить инструмент по результатам анализа, а также демонстрируют возможности анализатора по обнаружению ошибок.
    • Читатели видят, какие паттерны ошибок допускаются, набираются опыта, знакомятся с методикой статического анализа.

    В общем – чем не доказательство эффективности и пользы?

    Команды, уже использующие статический анализ



    Пока кто-то размышляет о том, стоит ли внедрять статический анализ в свой процесс разработки, некоторые команды уже вовсю его используют и извлекают пользу! Например, Rocksteady, Epic Games, ZeniMax Media, Oculus, Codemasters, Wargaming и другие (источник).

    Топ-10 ошибок из программного кода в видеоигровой индустрии


    Сразу стоит оговориться, что это не какой-то мега-глобальный 'топ', а те ошибки, найденные анализатором PVS-Studio в играх и игровых движках, которые показались мне наиболее интересными.

    Как обычно, для большего интереса предлагаю вам сначала самостоятельно попробовать найти ошибку в приведённом фрагменте кода, а лишь затем читать предупреждение анализатора и описание проблемы.

    Десятое место

    Источник: Ищем аномалии в X-Ray Engine



    На десятом месте расположилась ошибка из игрового движка X-Ray Engine, использовавшегося в играх S.T.A.L.K.E.R. Те, кто играл в игры из этой серии, наверняка помнят много забавных (и не очень) багов, возникавших во время игрового процесса. Особенно это касается S.T.A.L.K.E.R.: Clear Sky, в которую без патчей играть было вообще нереально (до сих пор помню баг, 'убивавший' все сохранения). Как показал анализ игрового движка — баги в коде действительно есть, и их достаточно много. Ниже представлен один из них.

    BOOL CActor::net_Spawn(CSE_Abstract* DC)
    {
      ....
      m_States.empty();
      ....
    }

    Предупреждение PVS-Studio: V530 The return value of function 'empty' is required to be utilized.

    Проблема проста — не используют возвращаемое логическое значение метода empty, указывающее, пуст ли контейнер. Судя по тому, что в приведённом выражении кроме вызова метода ничего нет, можно предположить, что разработчик хотел очистить контейнер, но ошибся, вызвав метод empty вместо clear.

    Кто-то может сказать, что это слишком простая ошибка для Топ-10. Но в этом и её прелесть! Несмотря на то, что вот так, взглядом со стороны, ошибка кажется достаточно простой и очевидной, подобные 'простые' ошибки не перестают появляться (и обнаруживаться) в различных проектах.

    Девятое место

    Источник: Долгожданная проверка CryEngine V

    Продолжаем раскрывать тему ошибок в игровых движках. На девятом месте — код из CryEngine V. В играх на этом движке я не замечал столько багов, сколько в играх на X-Ray Engine, но 'вскрытие' показало, что подозрительных фрагментов кода движок содержит немало.

    void CCryDXGLDeviceContext::
    OMGetBlendState(...., FLOAT BlendFactor[4], ....)
    {
      CCryDXGLBlendState::ToInterface(ppBlendState, m_spBlendState);
      if ((*ppBlendState) != NULL)
        (*ppBlendState)->AddRef();
      BlendFactor[0] = m_auBlendFactor[0];
      BlendFactor[1] = m_auBlendFactor[1];
      BlendFactor[2] = m_auBlendFactor[2];
      BlendFactor[2] = m_auBlendFactor[3];
      *pSampleMask = m_uSampleMask;
    }

    Предупреждение PVS-Studio: V519 The 'BlendFactor[2]' variable is assigned values twice successively. Perhaps this is a mistake.

    Как неоднократно упоминалось в наших статьях, никто не застрахован от опечаток. На практике также неоднократно подтверждалось, что статический анализ отлично справляется с обнаружением copy-paste и опечаток. Переписывали значения из массива m_auBlendFactor в BlendFactor, но случайно опечатались и два раза написали BlendFactor[2]. Из-за этой путаницы в BlendFactor[2] будет записано значение из m_auBlendFactor[3], а в BlendFactor[3] значение не поменяется.

    Восьмое место

    Источник: Единорог в космосе: проверяем исходный код 'Space Engineers'

    Немного изменим курс и перейдём от C++ к C#. Перед нами — код из проекта Space Engineers — игры-'песочницы' о строительстве и обслуживании космических структур. Сам я в игру не играл, но как сказал один из комментаторов статьи: "Я не сильно удивлён результатами :)". Что ж, интересные ошибки действительно удалось найти, ниже — две из них.

    public void Init(string cueName)
    {
      ....
      if (m_arcade.Hash    == MyStringHash.NullOrEmpty && 
          m_realistic.Hash == MyStringHash.NullOrEmpty)
        MySandboxGame.Log.WriteLine(string.Format(
          "Could not find any sound for '{0}'", cueName));
      else
      {
        if (m_arcade.IsNull)
          string.Format(
            "Could not find arcade sound for '{0}'", cueName);
        if (m_realistic.IsNull)
          string.Format(
            "Could not find realistic sound for '{0}'", cueName);
      }
    }

    Предупреждения PVS-Studio:
    • V3010 The return value of function 'Format' is required to be utilized.
    • V3010 The return value of function 'Format' is required to be utilized.

    Как видите, ошибки игнорирования возвращаемых значений методов встречаются не только в коде на C++, но и на C#. Метод String.Format составляет результирующую строку на основе строки формата и объектов для форматирования, после чего возвращает результат как возвращаемое значение метода. В коде выше в else-ветви есть два вызова string.Format, но их возвращаемые значения не используются. Скорее всего, необходимо было залогировать эти сообщения по аналогии с тем, как это сделано в then-ветви оператора if, используя метод MySandboxGame.Log.WriteLine.

    Седьмое место

    Источник: Проверка проекта Quake III Arena GPL

    Я уже говорил, что статический анализ хорошо обнаруживает опечатки? Пример ниже — ещё одно тому подтверждение.

    void Terrain_AddMovePoint(....) {
      ....
      x = ( v[ 0 ] - p->origin[ 0 ] ) / p->scale_x;
      y = ( v[ 1 ] - p->origin[ 1 ] ) / p->scale_x;
      ....
    }

    Предупреждение PVS-Studio: V537 Consider reviewing the correctness of 'scale_x' item's usage.

    Происходит запись в переменные x и y, но в обоих присвоениях в выражении вычисления значения используется подвыражение p->scale_x. Выглядит очень подозрительно и похоже на то, что во втором случае необходимо заменить выражение p->scale_x на p->scale_y.

    Шестое место

    Источник: Проверяем исходный C#-код Unity

    Компания Unity Technologies не так давно открыла исходный код собственного игрового движка — Unity. Мы не могли пройти мимо такого события и при анализе нашли немало интересных мест. Ниже — одно из них.

    public override bool IsValid()
    {
      ....
      return base.IsValid()
        && (pageSize >= 1 || pageSize <= 1000)
        && totalFilters <= 10;
    }

    Предупреждение PVS-Studio: V3063 A part of conditional expression is always true if it is evaluated: pageSize <= 1000.

    Имеем неверную проверку диапазона для pageSize. Скорее всего планировалось проверить, что значение pageSize лежит в пределах [1; 1000]. Однако допущена досадная опечатка: вместо оператора '&&' программист случайно написал '||'. Получается, что подвыражение на самом деле ничего не проверяет.

    Пятое место

    Источник: Анализируем ошибки в открытых компонентах Unity3D

    На соседнем месте расположилась интересная ошибка из компонентов Unity3D. Статья-источник была написана более чем за год до того, как был открыт исходный код движка Unity. Тем не менее, уже тогда можно было найти что-то интересное.

    public static CrawledMemorySnapshot Unpack(....)
    {
      ....
      var result = new CrawledMemorySnapshot
      {
        ....
        staticFields = packedSnapshot.typeDescriptions
                                     .Where(t =>
                                            t.staticFieldBytes != null &
                                            t.staticFieldBytes.Length > 0)
                                     .Select(t => UnpackStaticFields(t))
                                     .ToArray()
        ....
      };
      ....
    }

    Предупреждение PVS-Studio: V3080 Possible null dereference. Consider inspecting 't.staticFieldBytes'.

    Обратите внимание на лямбда-выражение, переданное в качестве аргумента методу Where. Судя по коду, коллекция typeDescriptions может содержать такие элементы, у которых член staticFieldBytes может иметь значение null. Именно поэтому, прежде чем обратиться к свойству Length, выполняется проверка, что staticFieldBytes != null. Вот только были перепутаны операторы, и вместо '&&' используется '&'. Это значит, что независимо от результата вычисления левого выражения (true \ false) правое выражение также будет вычисляться, из-за чего, если staticFieldBytes == null, при обращении к свойству Length будет сгенерировано исключение типа NullReferenceException. При использовании '&&' такой ситуации не возникло бы, так как, если staticFieldBytes == null, правая часть выражения не вычислялась бы.

    Несмотря на то, что Unity – единственный движок, дважды попавший в данный «Топ-10», энтузиастам это не мешает создавать на нём замечательных игр. В том числе – про борьбу с 'багами'.


    Четвертое место

    Источник: Анализ исходного кода движка Godot

    Иногда встречаются интересные ошибки, связанные с пропущенными ключевыми словами. Пример: создаётся объект исключения, но никак не используется, так как разработчик забывает указать ключевое слово throw. Встречаются такие ошибки и в C# проектах, и в C++ проектах. Пропущенное ключевое слово встретилось и в игровом движке Godot Engine.

    Variant Variant::get(const Variant& p_index, bool *r_valid) const 
    {
      ....
      if (ie.type == InputEvent::ACTION) 
      {
        if (str =="action") 
        {
          valid=true;
          return ie.action.action;
        }
        else if (str == "pressed") 
        {
          valid=true;
          ie.action.pressed;
        }
      }
      ....
    }

    Предупреждение PVS-Studio: V607 Ownerless expression 'ie.action.pressed'.

    В приведённом фрагменте кода видно, что в зависимости от значений ie.type и str хотели вернуть определённое значение типа Variant. Вот только один раз выражение возврата написали нормально — return ie.action.action;, а во второй раз забыли оператор return, из-за чего нужное значение не будет возвращено, а метод продолжит своё выполнение.

    Третье место

    Источник: PVS-Studio: анализируем код Doom 3

    Вот мы и подобрались к «Топ-3». Замыкает его небольшой фрагмент исходного кода из игры Doom 3. Как я говорил выше, то, что со стороны ошибка выглядит просто и может быть непонятно, как можно так ошибиться, ещё ничего не значит — на практике каких типов ошибок только не встретишь…

    void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
      ....
      memset( &statex, sizeof( statex ), 0 );
      ....
    }

    Предупреждение PVS-Studio: V575 The 'memset' function processes '0' elements. Inspect the third argument.

    Чтобы лучше понять проблему, стоит вспомнить сигнатуру функции memset:

    void* memset(void* dest, int ch, size_t count);

    Сопоставив сигнатуру функции с её вызовом, можно заметить, что последние два аргумента перепутаны местами. Как следствие — какой-то блок памяти, который требовалось обнулить, так и останется неизменённым.

    Второе место

    Второе место заняла ошибка, найденная в C# коде игрового движка Xenko.

    Источник: Ищем ошибки в игровом движке Xenko

    private static ImageDescription 
    CreateDescription(TextureDimension dimension, 
                      int width, int height, int depth, ....) { .... }
    
    public static Image New3D(int width, int height, int depth, ....)
    {
        return new Image(CreateDescription(TextureDimension.Texture3D,  
                                           width, width, depth,  
                                           mipMapCount, format, 1), 
                         dataPointer, 0, null, false);
    }

    Предупреждение PVS-Studio: V3065 Parameter 'height' is not utilized inside method's body.

    Ошибку допустили, передавая аргументы методу CreateDescription. Если посмотреть на его сигнатуру, можно увидеть, что второй, третий и четвёртый параметры имеют названия width, height и depth соответственно. При вызове же передаются аргументы width, width и depth. Подозрительно? Вот и анализатор тоже счёл это место достаточно подозрительным, чтобы выдать предупреждение.

    Первое место

    Источник: Долгожданная проверка Unreal Engine 4

    Возглавляет наш сегодняшний «Топ-10» ошибка из игрового движка Unreal Engine. Как и в случае со статьёй "Toп 10 ошибок в C++ проектах за 2017 год", увидев приведённую ниже ошибку, я сразу понял, кто должен возглавить список самых интересных ошибок.

    bool VertInfluencedByActiveBone(
      FParticleEmitterInstance* Owner,
      USkeletalMeshComponent* InSkelMeshComponent,
      int32 InVertexIndex,
      int32* OutBoneIndex = NULL);
    
    void UParticleModuleLocationSkelVertSurface::Spawn(....)
    {
      ....
      int32 BoneIndex1, BoneIndex2, BoneIndex3;
      BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE;
    
      if(!VertInfluencedByActiveBone(
            Owner, SourceComponent, VertIndex[0], &BoneIndex1) &&
         !VertInfluencedByActiveBone(
            Owner, SourceComponent, VertIndex[1], &BoneIndex2) && 
         !VertInfluencedByActiveBone(
            Owner, SourceComponent, VertIndex[2]) &BoneIndex3)
      {
      ....
    }

    Предупреждение PVS-Studio: V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator.

    Не удивлюсь, если, сопоставляя предупреждение анализатора и приведённый код, вы задались вопросом: «А где здесь, собственно, использование '&' вместо '&&'?». Но, если обратить внимание, что последний параметр функции VertInfluencedByActiveBone имеет значение по умолчанию, и упростить условное выражение оператора if, всё станет более понятно:

    if (!foo(....) && !foo(....) && !foo(....) & arg)

    Обратите особое внимание на последнее подвыражение:

    !VertInfluencedByActiveBone(Owner, SourceComponent, VertIndex[2])  
    &BoneIndex3

    Параметр со значением по умолчанию сыграл злую шутку — если бы значения по умолчанию не было, данный код бы просто не скомпилировался. Но так как оно есть, всё успешно компилируется, а ошибка не менее успешно маскируется. Вот это подозрительное место и заметил анализатор — инфиксная операция '&', в которой левый операнд имеет тип bool, а правый — int32.

    Заключение



    Надеюсь, мне удалось показать, что статический анализ будет полезен при разработке игр и игровых движков и является ещё одним ответом на вопрос о повышении качества кода (и конечного продукта, как следствие). Если вы занимаетесь разработкой в сфере видеоигровой индустрии, то просто обязаны рассказать коллегам о статическом анализе и показать эту статью. Думаете с чего начать? Начните с PVS-Studio.



    Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Sergey Vasiliev. Static Analysis in Video Game Development: Top 10 Software Bugs

    Прочитали статью и есть вопрос?
    Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio, версия 2015. Пожалуйста, ознакомьтесь со списком.
    PVS-Studio
    451,00
    Static Code Analysis for C, C++, C# and Java
    Поделиться публикацией

    Похожие публикации

    Комментарии 26

      +6
      Проблема проста — не используют возвращаемое логическое значение метода empty, указывающее, пуст ли контейнер. Судя по тому, что в приведённом выражении кроме вызова метода ничего нет, можно предположить, что разработчик хотел очистить контейнер, но ошибся, вызвав метод empty вместо clear.


      Проблемы не возникло бы, если бы метод назывался is_empty.
        0
        Автор оригинальной статьи про проверку X-Ray Engine тоже обратил на это внимание :)
          0
          Особенно «весело» при использовании MFC и STL в одном проекте. У той же CString::Empty() — очистка строки.
            –4
            и уж наверняка бы её не возникло, называйся метод get_container_size_is_equal_to_zero(); (сарказм)
            0
            10. Как заметили выше, изначальная ошибка не в вызове неправильного метода, а в неправильном именовании метода. Название должно давать четкое понимание, что метод делает.
            9. Copy-Paste — зло! Используйте циклы с автоопределением размера массивов. И статический ассерт с проверкой что бы размеры массивов были одинаковы.
            8. При создании функции логгирования нужно создать вариант с переменным листом аргументов и формирование строки засунуть внутрь WriteLine() — это проще чем при каждом вызове ещё и string.Format() звать(не знаю на счёт C#, а вот в C++ так делал).
            7, 6, 5. Все мы люди, все мы ошибаемся — с опечатками ничего не поделаешь.
            4. Правила MISRA указывают, что в функции должен быть один вход и один выход. Не стоит раскидывать return'ы по всем внутренностям функции. Кстати, те же правила указывают, что цепочка if-else if обязательно должна заканчиваться else, даже если в нем будет пусто.
            3, 2, 1. Опять опечатки.
              0
              При этом все ошибки фиксятся на кодревью
                +2
                Ха-ха. :) 13645 ошибок найденных нами в открытых проектах.
                  0
                  Ага, особенно последняя.
                  Но примерно половину ошибок можно было бы избежать, если бы использовалась правильная методология написания кода.
                    0
                    Мы много общаемся с руководителями разработок разных компаний на тему контроля качества кода. Так вот, в общем случае, кодревью служит только для проверки логики работы внесённых изменений в код, немножко code style и практически ничего (из серии «случайно бросилось в глаза») по ляпам разного характера.
                  0
                  Вообще предупреждение на первое место хорошо бы изменить: у разработчика возникнет ощущение, что ваш анализатор просто ошибся. Без вашего детального разъяснения понять где ошибка реально тяжело.
                    +1
                    А анализатор умный что ли? Он "видит" примерно то, что показал автор когда foo() использовал и применяет правила. Не удивлюсь, если авторы анализатора сами подумали что он ошибся и полезли с отладчиком спотреть почему.
                    0

                    Эх, чем больше смотрю на эти перечни "тупых" или "непреднамеренных" ошибок типа копипаста и т.п., тем больше задаюсь вопросом, сколько же тогда ошибок кроется в рантайме (когда код по задумке разработчика написан верно, так, как он и хотел, но сама логика программы при этом не верна)
                    Если программа работает, это не значит, что в ней нет ошибок.
                    Если в программе нет ошибок, это не значит, что она работает правильно.

                      0
                      И хотя я понимаю, что авторы этой статьи не смогут реализовать это, но помечтать вслух не запрещено ведь?
                      Круто было бы, если бы возле каждой проверки был описан результат-баг в реальном продукте. К примеру, вызвал empty вместо clear — массив не очистился, потом метод Х использовал этот массив, вернул неправильные данные методу В и тот сохранил пустой файл вместо файла с данными.
                        +1
                        Это делать можно, но это очень трудоёмко. По крайней мере регулярно писать подобные статьи мы не осилим.
                        +1
                        Какой только фигни в коде не напишешь когда руководитель департамента теребит каждые полчаса «где релиз, когда релиз» а программистов по пальцам одной руки пересчитать можно
                          0
                          31 программист это не так уж мало /s
                          0
                          Каждый раз, как читаю о PVS возникает желание вернуться на C++. Автоматический поиск багов вызывает чувство уюта.: )
                          Нет ли в планах JS? Неиспользуемые параметры метода или ошибки в логических условиях выглядят реализуемо для динамического языка.
                            +1
                            JS — нет. В планах Java.
                            0
                            (del)
                              0
                              В Chromium недавно всплыл интересный баг, который, похоже, вполне мог быть отловлен статическим анализом:
                              https://bugs.chromium.org/p/chromium/issues/detail?id=835506
                              Краткое описание на русском
                              Отлавливали ли вы этот баг в прошлых проверках Chromium?
                                +1
                                За такое руки нужно отбивать! Это я не про баг, это я про его решение. Не должно быть static внутри функции, все переменные которые static должны быть объявлены в приватной части класса и документированы.
                                Один раз столкнулся со странным поведением — вызываю функцию класса, а она не делает того, что нужно. А оказалось у нее внутри статическая переменная в которую она сохраняет переданный параметр и на следующих входах проверяет новый параметр с предыдущим и от этого меняется поведение. И нигде такое поведение не было документировано. И вот такое статическим анализатором уже не найдешь.
                                  0
                                  По всей видимости нет. Но у нас при написании статей и нет задачи найти как можно больше багов в проекте. :)
                                    0
                                    Вопрос был еще и в том, может ли PVS-Studio находить подобную ошибку?
                                    Суть бага:

                                    void buggy_function()
                                    {
                                    float* table = nullptr;
                                    if (some_condition) {
                                    float another_table[] = { 0.1, 0.2, 0,3 };
                                    table = another_table;
                                    }
                                    some_other_function(table);
                                    }

                                    Память выделенная на стеке продолжает использоваться за пределами блока через указатель, что раньше прокатывало, но при переходе на новую версию компилятора привело к трудноуловимому багу.
                                      0
                                      Нет, пока такую ошибку анализтор не найдёт.
                                        0
                                        зато такую ошибку прекрасно найдет сам Clang/gcc, точнее AddressSanitizer github.com/google/sanitizers/wiki/AddressSanitizerExampleUseAfterScope
                                          +1
                                          Пфф… В таком примере и PVS-Studio её находит:

                                          V506 CWE-562 Pointer to local variable 'x' is stored outside the scope of this variable. Such a pointer will become invalid. consoleapplication2017.cpp 31

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.