Salah satu senario terkini untuk menggunakan penganalisis PVS-Studio ialah penyepaduannya dengan sistem CI. Dan walaupun analisis projek PVS-Studio daripada hampir mana-mana sistem integrasi berterusan boleh dibina ke dalam beberapa arahan sahaja, kami terus menjadikan proses ini lebih mudah. PVS-Studio kini mempunyai sokongan untuk menukar output penganalisis kepada format untuk TeamCity - Jenis Pemeriksaan TeamCity. Mari lihat bagaimana ia berfungsi.
Maklumat tentang perisian yang digunakan
Maklumat tentang projek yang sedang dikaji
Mari cuba fungsi ini dengan contoh praktikal - mari analisa projek OpenRCT2.
pelarasan
Untuk menjimatkan masa, saya mungkin akan melangkau proses pemasangan dan bermula dari saat saya menjalankan pelayan TeamCity pada komputer saya. Kita perlu pergi ke: localhost:{port specified during the installation process} (dalam kes saya, localhost:9090) dan masukkan data kebenaran. Selepas masuk kami akan disambut oleh:
Klik pada butang Cipta Projek. Seterusnya, pilih Secara Manual dan isikan medan.
Selepas menekan butang Buat, kami disambut oleh tetingkap dengan tetapan.
Jom klik Buat konfigurasi binaan.
Isi medan dan klik Buat. Kami melihat tetingkap yang meminta anda memilih sistem kawalan versi. Memandangkan sumber telah pun berada di dalam negara, klik Langkau.
Akhirnya, kita beralih ke tetapan projek.
Mari tambah langkah pemasangan, untuk melakukan klik ini: Langkah bina -> Tambah langkah binaan.
Di sini kami memilih:
- Jenis pelari -> Baris Perintah
- Jalankan -> Skrip Tersuai
Memandangkan kami akan melakukan analisis semasa penyusunan projek, pemasangan dan analisis harus menjadi satu langkah, jadi isikan medan tersebut Skrip Tersuai:
Kami akan melihat langkah individu kemudian. Adalah penting untuk memuatkan penganalisis, memasang projek, menganalisisnya, mengeluarkan laporan dan memformatnya hanya memerlukan sebelas baris kod.
Perkara terakhir yang perlu kita lakukan ialah menetapkan pembolehubah persekitaran, yang telah saya gariskan beberapa cara untuk meningkatkan kebolehbacaannya. Untuk melakukan ini, mari kita teruskan: Parameter -> Tambah parameter baharu dan tambah tiga pembolehubah:
Anda hanya perlu menekan butang Main di sudut kanan atas. Semasa projek sedang dipasang dan dianalisis, saya akan memberitahu anda tentang skrip.
Skrip langsung
Pertama, kita perlu memuat turun pengedaran PVS-Studio terkini. Untuk ini kami menggunakan pengurus pakej Chocolatey. Bagi mereka yang ingin mengetahui lebih lanjut mengenai perkara ini, ada yang sepadan
choco install pvs-studio -y
Seterusnya, mari lancarkan utiliti penjejakan binaan projek CLMonitor.
%CLmon% monitor β-attach
Kemudian kami akan membina projek sebagai pembolehubah persekitaran MSB ialah laluan ke versi MSBuild yang perlu saya bina
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Mari masukkan kunci log masuk dan lesen untuk PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Selepas binaan selesai, jalankan CLMonitor sekali lagi untuk menjana fail praproses dan analisis statik:
%CLmon% analyze -l "c:ptest.plog"
Kemudian kami akan menggunakan utiliti lain daripada pengedaran kami. PlogConverter menukar laporan daripada format standard kepada format khusus TeamCity. Terima kasih kepada ini, kami akan dapat melihatnya terus dalam tetingkap binaan.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
Langkah terakhir ialah memaparkan laporan berformat dalam stdout, di mana ia akan diambil oleh penghurai TeamCity.
type "C:tempptest.plog_TeamCity.txt"
Kod skrip penuh:
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"
Sementara itu, pemasangan dan analisis projek telah berjaya diselesaikan, kita boleh pergi ke tab Projek dan pastikan ia.
Sekarang mari kita klik pada Jumlah Pemeriksaanuntuk pergi melihat laporan penganalisis:
Amaran dikumpulkan mengikut nombor peraturan diagnostik. Untuk menavigasi kod, anda perlu mengklik pada nombor baris dengan amaran. Mengklik pada tanda soal di penjuru kanan sebelah atas akan membuka anda tab baharu dengan dokumentasi. Anda juga boleh menavigasi kod dengan mengklik pada nombor baris dengan amaran penganalisis. Navigasi dari komputer jauh adalah mungkin apabila menggunakan SourceTreeRoot penanda. Sesiapa yang berminat dengan mod operasi penganalisis ini boleh membiasakan diri dengan bahagian yang sepadan
Melihat keputusan penganalisis
Sekarang setelah kita selesai mengatur dan mengkonfigurasi binaan, mari kita lihat beberapa amaran menarik yang terdapat dalam projek yang sedang kita lihat.
Amaran 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;
}
Penganalisis melihat ralat yang selepas memperuntukkan memori secara dinamik CreateObject, apabila pengecualian berlaku, memori tidak dikosongkan, dan kebocoran memori berlaku.
Amaran 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),
....
};
Beberapa orang selain daripada penganalisis statik boleh lulus ujian perhatian ini. Contoh salin-tampal ini bagus untuk sebab ini.
Amaran N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Sudah tentu, menggunakan pembolehubah dengan nama yang sama dalam kelas asas dan dalam keturunan tidak selalu menjadi ralat. Walau bagaimanapun, teknologi pewarisan sendiri menganggap bahawa semua bidang kelas induk terdapat dalam kelas anak. Dengan mengisytiharkan medan dengan nama yang sama dalam waris, kami memperkenalkan kekeliruan.
Amaran N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Mari kita lihat lebih dekat. Ungkapan gambarArah/8 akan menjadi palsu jika gambarArah berada dalam julat dari -7 hingga 7. Bahagian kedua: (gambarArah / 8) != 3 cek gambarArah kerana berada di luar julat: dari -31 hingga -24 dan dari 24 hingga 31, masing-masing. Nampaknya agak pelik bagi saya untuk menyemak nombor untuk dimasukkan dalam julat tertentu dengan cara ini dan, walaupun tiada ralat dalam sekeping kod ini, saya akan mengesyorkan agar anda menulis semula syarat ini untuk menjadi lebih jelas. Ini akan menjadikan hidup lebih mudah bagi orang yang akan membaca dan mengekalkan kod ini.
Amaran 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;
....
}
....
}
Serpihan kod ini berkemungkinan besar diperoleh melalui penyahkompilasi. Kemudian, berdasarkan ulasan yang ditinggalkan, sebahagian daripada kod yang tidak berfungsi telah dialih keluar. Walau bagaimanapun, masih terdapat beberapa operasi lagi cursorId, yang juga tidak masuk akal.
Amaran 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); // <=
}
....
}
Kod ini agak mudah untuk dibetulkan; anda hanya perlu menyemaknya untuk kali ketiga Pemain pada penuding nol, atau tambahkannya pada isi pernyataan bersyarat. Saya akan mencadangkan pilihan kedua:
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);
}
}
....
}
Amaran 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));
....
}
....
}
Anda boleh menyingkirkan baris kod yang sukar dibaca dalam satu masa dan menyelesaikan masalah dengan menyemak nullptr. Saya cadangkan menukar kod seperti berikut:
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);
....
}
....
}
Amaran N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Kod itu kelihatan agak pelik. Nampaknya saya ada kesilapan menaip sama ada dalam keadaan atau semasa menetapkan semula pembolehubah ColumnHeaderPressedCurrentState makna palsu.
Output
Seperti yang kita dapat lihat, menyepadukan penganalisis statik PVS-Studio ke dalam projek TeamCity anda agak mudah. Untuk melakukan ini, cukup untuk menulis hanya satu fail konfigurasi kecil. Menyemak kod akan membolehkan anda mengenal pasti masalah sejurus selepas pemasangan, yang akan membantu menghapuskannya apabila kerumitan dan kos perubahan masih rendah.
Jika anda ingin berkongsi artikel ini dengan penonton berbahasa Inggeris, sila gunakan pautan terjemahan: Vladislav Stolyarov.
Sumber: www.habr.com