PVS-Studio анализаторын пайдаланудың ең қазіргі сценарийлерінің бірі оның CI жүйелерімен интеграциясы болып табылады. Кез келген үздіксіз интеграциялық жүйеден PVS-Studio жобасын талдауды бірнеше командаларға салуға болатынына қарамастан, біз бұл процесті одан да ыңғайлы етуді жалғастырамыз. PVS-Studio енді анализатор шығысын TeamCity пішіміне түрлендіруге қолдау көрсетеді - TeamCity Inspections Type. Оның қалай жұмыс істейтінін көрейік.
Қолданылатын бағдарламалық құрал туралы ақпарат
Зерттелетін жоба туралы ақпарат
Давайте попробуем данную функциональность на практическом примере – проанализируем проект OpenRCT2.
реттеу
Уақытты үнемдеу үшін мен орнату процесін өткізіп жіберіп, менің компьютерімде TeamCity сервері жұмыс істеп тұрған кезден бастайтын шығармын. Бізге келесіге өту керек: localhost:{орнату процесінде көрсетілген порт} (менің жағдайда, localhost:9090) және авторизация деректерін енгізіңіз. Кіргеннен кейін бізді қарсы алады:
Жоба жасау түймесін басыңыз. Содан кейін «Қолмен» опциясын таңдап, өрістерді толтырыңыз.
Түймені басқаннан кейін жасау, бізді параметрлері бар терезе қарсы алады.
Басайық Құрастыру конфигурациясын жасаңыз.
Өрістерді толтырып, түймесін басыңыз жасау. Біз нұсқаны басқару жүйесін таңдауды сұрайтын терезені көреміз. Дереккөздер жергілікті жерде орналасқандықтан, түймесін басыңыз Өткізіңіз.
Соңында біз жоба параметрлеріне көшеміз.
Бұл әрекетті орындау үшін құрастыру қадамдарын қосамыз: Build steps -> Add build step.
Мұнда біз таңдаймыз:
- Жүгірушінің түрі -> Пәрмен жолы
- Іске қосу -> Теңшелетін сценарий
Біз жобаны құрастыру кезінде талдау жасайтындықтан, құрастыру және талдау бір қадам болуы керек, сондықтан өрісті толтырыңыз Таңдамалы сценарий:
На отдельных шагах мы остановимся позже. Важно, чтобы загрузка анализатора, сборка проекта, его анализ, вывод отчёта и его форматирование заняло всего одиннадцать строк кода.
Последнее, что нам нужно сделать, — установить переменные окружения, которыми я обозначил некоторые пути для улучшения их читабельности. Для этого перейдём: Параметрлер -> Жаңа параметр қосу и добавим три переменные:
Бар болғаны түймені басу керек жүгіру жоғарғы оң жақ бұрышында. Жоба құрастырылып, талданып жатқанда, мен сценарий туралы айтып беремін.
Тікелей сценарий
Біріншіден, біз соңғы PVS-Studio дистрибутивін жүктеп алуымыз керек. Ол үшін Chocolatey пакетінің менеджерін қолданамыз. Бұл туралы көбірек білгісі келетіндер үшін сәйкес бар
choco install pvs-studio -y
Әрі қарай, CLMonitor жобасын құруды қадағалау қызметтік бағдарламасын іске қосамыз.
%CLmon% monitor –-attach
Содан кейін жобаны орта айнымалысы ретінде құрастырамыз MSB выступает путь к нужной мне для сборки версии MSBuild
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Введём логин и ключ лицензии PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Құрастыру аяқталғаннан кейін алдын ала өңделген файлдарды және статикалық талдауды жасау үшін CLMonitor бағдарламасын қайта іске қосыңыз:
%CLmon% analyze -l "c:ptest.plog"
Содан кейін біз дистрибутивтен басқа қызметтік бағдарламаны қолданамыз. PlogConverter есепті стандартты пішімнен TeamCity арнайы пішіміне түрлендіреді. Осының арқасында біз оны тікелей құрастыру терезесінде көре аламыз.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
Соңғы қадам пішімделген есепті ішінде көрсету болып табылады stdout, оны TeamCity талдаушысы таңдайды.
type "C:tempptest.plog_TeamCity.txt"
Полный код скрипта:
choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"
Әзірге жобаны құрастыру және талдау сәтті аяқталды, қойындыға өтуге болады жобалар и убедиться в этом.
Енді басайық Тексерулердің барлығы, чтоб перейти к просмотру отчёта анализатора:
Ескертулер диагностикалық ереже нөмірлері бойынша топтастырылған. Код бойынша шарлау үшін ескертуі бар жол нөмірін басу керек. Жоғарғы оң жақ бұрыштағы сұрақ белгісін басу сізге құжаттамалары бар жаңа қойындыны ашады. Сондай-ақ, анализатор ескертуі бар жол нөмірін басу арқылы код бойынша шарлауға болады. Пайдалану кезінде қашықтағы компьютерден шарлау мүмкін болады SourceTreeRoot маркера. Тот, кому интересен данный режим работы анализатора, может ознакомиться с соответствующим разделом
Анализатордың нәтижелерін қарау
Енді құрастыруды орналастыру және конфигурациялауды аяқтағаннан кейін біз қарастырып жатқан жобада табылған кейбір қызықты ескертулерді қарастырайық.
N1 ескерту
Object* CreateObjectFromJson(....)
{
Object* result = nullptr;
....
result = CreateObject(entry);
....
if (readContext.WasError())
{
throw std::runtime_error("Object has errors");
}
....
}
Object* CreateObject(const rct_object_entry& entry)
{
Object* result;
switch (entry.GetType())
{
case OBJECT_TYPE_RIDE:
result = new RideObject(entry);
break;
case OBJECT_TYPE_SMALL_SCENERY:
result = new SmallSceneryObject(entry);
break;
case OBJECT_TYPE_LARGE_SCENERY:
result = new LargeSceneryObject(entry);
break;
....
default:
throw std::runtime_error("Invalid object type");
}
return result;
}
Анализатор жадты динамикалық түрде бөлгеннен кейін қатені байқады CreateObject, при возникновении исключения память не очищается, соответственно, возникает утечка памяти.
N2 ескерту
static uint64_t window_cheats_page_enabled_widgets[] =
{
MAIN_CHEAT_ENABLED_WIDGETS |
(1ULL << WIDX_NO_MONEY) |
(1ULL << WIDX_ADD_SET_MONEY_GROUP) |
(1ULL << WIDX_MONEY_SPINNER) |
(1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
(1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
(1ULL << WIDX_ADD_MONEY) |
(1ULL << WIDX_SET_MONEY) |
(1ULL << WIDX_CLEAR_LOAN) |
(1ULL << WIDX_DATE_SET) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_MONTH_UP) |
(1ULL << WIDX_MONTH_DOWN) |
(1ULL << WIDX_YEAR_BOX) |
(1ULL << WIDX_YEAR_UP) |
(1ULL << WIDX_YEAR_DOWN) |
(1ULL << WIDX_DAY_BOX) |
(1ULL << WIDX_DAY_UP) |
(1ULL << WIDX_DAY_DOWN) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_DATE_GROUP) |
(1ULL << WIDX_DATE_RESET),
....
};
Статикалық анализатордан басқа аз адамдар бұл зейінділік сынағынан өте алады. Көшіру-қою үлгісі дәл осы себепті жақсы.
N3 ескертулер
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Әрине, негізгі сыныпта және ұрпақта бірдей атпен айнымалыны пайдалану әрқашан қате емес. Дегенмен, мұрагерлік технологияның өзі ата-аналық сыныптың барлық өрістері еншілес сыныпта бар деп болжайды. Мұрагердегі аттас өрістерді жариялау арқылы біз шатасуды тудырамыз.
N4 ескерту
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Толығырақ қарастырайық. Өрнек imageDirection/8 жалған болады, егер imageDirection находится в диапазоне от -7 до 7. Вторая часть: (imageDirection / 8) != 3 чектер imageDirection на нахождение вне диапазона: от -31 до -24 и от 24 до 31 соответственно. Мне кажется довольно странным проверять числа на вхождение в определённый диапазон таким способом и, даже если в данном фрагменте кода нет ошибки, я бы рекомендовал переписать данные условия на более явные. Это существенно упростило бы жизнь людям, которые будут читать и поддерживать этот код.
N5 ескерту
void process_mouse_over(....)
{
....
switch (window->widgets[widgetId].type)
{
case WWT_VIEWPORT:
ebx = 0;
edi = cursorId; // <=
// Window event WE_UNKNOWN_0E was called here,
// but no windows actually implemented a handler and
// it's not known what it was for
cursorId = edi; // <=
if ((ebx & 0xFF) != 0)
{
set_cursor(cursorId);
return;
}
break;
....
}
....
}
Данный фрагмент кода, скорее всего, был получен путем декомпиляции. Затем, судя по оставленному комментарию, была удалена часть нерабочего кода. Однако осталась пара операций над курсор идентификаторы, бұл да көп мағынаға ие емес.
N6 ескерту
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player) // <=
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
}
newPlayers.push_back(player->Id); // <=
}
....
}
Бұл кодты түзету өте оңай, оны үшінші рет тексеру керек ойыншы нөлдік көрсеткішке немесе оны шартты мәлімдеменің негізгі бөлігіне қосыңыз. Мен екінші нұсқаны ұсынар едім:
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player)
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
newPlayers.push_back(player->Id);
}
}
....
}
N7 ескерту
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
....
}
else
{
....
entry.name = (name == nullptr ? "" : json_string_value(name));
....
}
....
}
Сіз оқуға қиын код жолынан бір сәтте құтылып, мәселені тексеру арқылы шеше аласыз. nullptr. Мен кодты келесідей өзгертуді ұсынамын:
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
name = ""
....
}
else
{
....
entry.name = json_string_value(name);
....
}
....
}
N8 ескерту
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Код выглядит довольно странно. Мне кажется, имела место быть опечатка либо в условии, либо при повторном присвоении переменной ColumnHeaderPressedCurrentState мағынасы жалған.
қорытынды
Көріп отырғанымыздай, PVS-Studio статикалық анализаторын TeamCity жобасына біріктіру өте қарапайым. Ол үшін бір ғана шағын конфигурация файлын жазу жеткілікті. Кодты тексеру құрастырудан кейін бірден проблемаларды анықтауға мүмкіндік береді, бұл өзгертулердің күрделілігі мен құны әлі де төмен болған кезде оларды жоюға көмектеседі.
Егер сіз осы мақаланы ағылшын тілінде сөйлейтін аудиториямен бөліскіңіз келсе, аударма сілтемесін пайдаланыңыз: Владислав Столяров.
Ақпарат көзі: www.habr.com