Мне понятна ваша логика. Однако, если следовать ей, то можно сделать вывод, что дефолтная ветвь в GetNumVectorElements является недостижимым кодом:
static inline int GetNumVectorElements(VectorSize sz)
{
switch (sz)
{
case V_Single: return 1;
case V_Pair: return 2;
case V_Triple: return 3;
case V_Quad: return 4;
default: return 0; //unreachable code
}
}
Недостижимый код тоже является ошибкой и в данном случае можно сказать, что является меньшим злом. Итак, имеем недостижимый код в виде default: return 0;
Можно убрать эту ветвь, но тогда получим предупреждение от компилятора, что control flow graph функции имеет путь без возвращаемого значения. Хорошо, заменим возвращаемое значение на std::optional и на этом казалось бы всё.
Но! Можно всё же заметить, что VectorSize имеет такой вариант значения как V_Invalid = -1, который как раз обрабатывается этой ветвью и может прийти из указанной вами функции GetVecSize.
Предположим даже, что обёртка MIPSOpcode , которая представляет из себя Memory::Opcode всегда будет иметь значения из того же диапазона, что и uint32_t, а переменные a и b , которые удачно объявлены как int, никогда не будут отрицательными. И результат каста (VectorSize)(a + b + 1) тоже никогда не будет V_Invalid (-1).
Есть ли гарантия, что в результате рефакторинга или других изменений в коде всё это не рассыплется как карточный домик?
На текущий момент таких планов нет, но никто не знает, как может сложиться судьба дальше. Например, у нас недавно был внутренний хакатон, и на нем мы писали прототип анализатора для языка Lua. Кстати, скоро опубликуем про это статью :)
Насчёт требования по отсутствию STL не знал, спасибо. Однако у них она все же используется, если сделать поиск в коде по std:: можно найти кое-что. По поводу же данного исправления, опять таки это лишь вариант исправления в общем случае. Кажется, они уже исправляли похожую проблему. По поиску можно найти, например, такой вариант.
Можно воспользоваться std::ptrdiff_t (или аналогом, если не хочется использовать стандартную библиотеку) вместо int64_t. Подобрать полностью подходящий вариант исправления могут только сами разработчики, так как они знают все тонкости проекта. Я лишь предложил варианты исправления в общем случае, а дальше нужно смотреть, что подойдет лучше. Я, кстати, создал issue у них на github, и они отписали уже по всем фрагментам.
Да, например, есть такая статья. А так мы регулярно проверяем сами себя во время ночных сборок на сервере, и разработчикам приходят уведомления на почту, если есть срабатывания.
Так, а минусы будут? :D Блог компании PVS-Studio бесплатно находит и расписывает чужие ошибки, предлагая исправленные варианты кода. Как минимум это экономит время и силы разработчиков на поиск и исправление, как максимум обучает других не совершать подобные ошибки в своём коде :)
Сложно. Для этого надо, чтобы все наши анализаторы работали через одно обобщенное внутреннее представление в виде AST (Abstract Syntax Tree). Тогда можно будет запустить какой-то общий набор диагностических правил.
Для каждого языка программирования строятся различные AST, которые учитывают его семантику. К сожалению, обобщить все многообразие AST для целей статического анализа так легко не получится – будет утерян контекст исходного кода.
Я бы сказал всё зависит от области применения. В тех областях, где производительность и эффективность не на первом месте, высокоуровневые языки позволяют сэкономить время программиста, упрощая ему жизнь. Для бизнеса это может оказаться выгоднее, чем писать компактный и эффективный код (надо отметить, что высокоуровневый язык != некомпактный и неэффективный код, зачастую наоборот (например, если речь про C++)). Но всё должно быть в меру и описанная вами ситуация, к сожалению, не редкость и действительно пугает.
Насколько мне известно, допустимы оба варианта написания, в данном случае для акцентирования внимания на выполнении деления по модулю использован вариант с предлогом "by".
Да, вы правы, оригинальный DOOM 1993 года был написан на C, но к счастью (или к сожалению) время не стоит на месте, и люди портируют старые игры, используя более высокоуровневые языки.
Всегда пожалуйста! Это Вам спасибо за Ваши труды. Я всё же рекомендую, если дойдут руки, самим провести анализ и разобрать срабатывания, т.к. в статье описаны далеко не все случаи. Также, если времени разбираться со всеми срабатываниями пока нет, можно подавить существующие и разбирать только относящиеся к новому коду, а к старым возвращаться по возможности.
Спасибо за интересное замечание!
Мне понятна ваша логика. Однако, если следовать ей, то можно сделать вывод, что дефолтная ветвь в
GetNumVectorElements
является недостижимым кодом:static inline int GetNumVectorElements(VectorSize sz) { switch (sz) { case V_Single: return 1; case V_Pair: return 2; case V_Triple: return 3; case V_Quad: return 4; default: return 0; //unreachable code } }
Недостижимый код тоже является ошибкой и в данном случае можно сказать, что является меньшим злом. Итак, имеем недостижимый код в виде
default: return 0;
Можно убрать эту ветвь, но тогда получим предупреждение от компилятора, что control flow graph функции имеет путь без возвращаемого значения. Хорошо, заменим возвращаемое значение на
std::optional
и на этом казалось бы всё.Но! Можно всё же заметить, что
VectorSize
имеет такой вариант значения какV_Invalid = -1
, который как раз обрабатывается этой ветвью и может прийти из указанной вами функцииGetVecSize
.Предположим даже, что обёртка
MIPSOpcode
, которая представляет из себяMemory::Opcode
всегда будет иметь значения из того же диапазона, что иuint32_t
, а переменныеa
иb
, которые удачно объявлены какint
, никогда не будут отрицательными. И результат каста(VectorSize)(a + b + 1)
тоже никогда не будетV_Invalid
(-1).Есть ли гарантия, что в результате рефакторинга или других изменений в коде всё это не рассыплется как карточный домик?
Спасибо, рады были стараться!
Спасибо, поправил.
Согласен, добавил чуть больше конкретики)
А вот и обещанная статья.
На текущий момент таких планов нет, но никто не знает, как может сложиться судьба дальше. Например, у нас недавно был внутренний хакатон, и на нем мы писали прототип анализатора для языка Lua. Кстати, скоро опубликуем про это статью :)
Насчёт требования по отсутствию STL не знал, спасибо. Однако у них она все же используется, если сделать поиск в коде по std:: можно найти кое-что. По поводу же данного исправления, опять таки это лишь вариант исправления в общем случае. Кажется, они уже исправляли похожую проблему. По поиску можно найти, например, такой вариант.
Можно воспользоваться std::ptrdiff_t (или аналогом, если не хочется использовать стандартную библиотеку) вместо int64_t. Подобрать полностью подходящий вариант исправления могут только сами разработчики, так как они знают все тонкости проекта. Я лишь предложил варианты исправления в общем случае, а дальше нужно смотреть, что подойдет лучше.
Я, кстати, создал issue у них на github, и они отписали уже по всем фрагментам.
Да, ссылка. Там их уже, кстати, немало от нас :D
Да, например, есть такая статья. А так мы регулярно проверяем сами себя во время ночных сборок на сервере, и разработчикам приходят уведомления на почту, если есть срабатывания.
Так, а минусы будут? :D
Блог компании PVS-Studio бесплатно находит и расписывает чужие ошибки, предлагая исправленные варианты кода. Как минимум это экономит время и силы разработчиков на поиск и исправление, как максимум обучает других не совершать подобные ошибки в своём коде :)
Спасибо за интересный вопрос.
Сложно. Для этого надо, чтобы все наши анализаторы работали через одно обобщенное внутреннее представление в виде AST (Abstract Syntax Tree). Тогда можно будет запустить какой-то общий набор диагностических правил.
Для каждого языка программирования строятся различные AST, которые учитывают его семантику. К сожалению, обобщить все многообразие AST для целей статического анализа так легко не получится – будет утерян контекст исходного кода.
В начале статьи есть упоминание и ссылка на его проверку.
Справедливое замечание с учётом характера статьи :D
Я бы сказал всё зависит от области применения. В тех областях, где производительность и эффективность не на первом месте, высокоуровневые языки позволяют сэкономить время программиста, упрощая ему жизнь. Для бизнеса это может оказаться выгоднее, чем писать компактный и эффективный код (надо отметить, что высокоуровневый язык != некомпактный и неэффективный код, зачастую наоборот (например, если речь про C++)). Но всё должно быть в меру и описанная вами ситуация, к сожалению, не редкость и действительно пугает.
Насколько мне известно, допустимы оба варианта написания, в данном случае для акцентирования внимания на выполнении деления по модулю использован вариант с предлогом "by".
Согласен, выглядит жутко :D. Даже с подсказкой анализатора мне понадобилось определённое количество времени, чтобы разобраться, что там происходит.
Да, вы правы, оригинальный DOOM 1993 года был написан на C, но к счастью (или к сожалению) время не стоит на месте, и люди портируют старые игры, используя более высокоуровневые языки.
Всегда пожалуйста! Это Вам спасибо за Ваши труды.
Я всё же рекомендую, если дойдут руки, самим провести анализ и разобрать срабатывания, т.к. в статье описаны далеко не все случаи. Также, если времени разбираться со всеми срабатываниями пока нет, можно подавить существующие и разбирать только относящиеся к новому коду, а к старым возвращаться по возможности.