目前使用 PVS-Studio 分析儀的場景之一是其與 CI 系統的整合。 儘管幾乎任何持續整合系統的 PVS-Studio 專案分析都可以建置到幾個命令中,但我們繼續讓這個過程變得更加方便。 PVS-Studio 現在支援將分析器輸出轉換為 TeamCity - TeamCity 檢查類型的格式。 讓我們看看它是如何工作的。
有關所使用軟體的信息
有關正在研究的項目的信息
讓我們透過一個實際範例來嘗試此功能 - 讓我們分析 OpenRCT2 專案。
調整
為了節省時間,我可能會跳過安裝過程,從 TeamCity 伺服器在我的電腦上運行的那一刻開始。 我們需要存取: localhost:{安裝過程中指定的連接埠}(在我的例子中為 localhost:9090)並輸入授權資料。 進入後,迎接我們的是:
點選“建立專案”按鈕。 接下來,選擇手動並填寫欄位。
按下按鈕後 創建,我們會看到一個有設定的視窗。
我們點擊一下 建立建置配置.
填寫欄位並點擊 創建。 我們看到一個窗口,要求您選擇版本控制系統。 由於來源已位於本機,因此按一下 跳至.
最後,我們繼續進行專案設定。
讓我們新增組裝步驟,為此點擊: 建置步驟 -> 新增建置步驟.
這裡我們選擇:
- 運行器類型 -> 命令列
- 運行 -> 自訂腳本
由於我們會在專案編譯時進行分析,所以組裝和分析應該是一步,所以填寫該字段 自定義腳本:
我們稍後將討論各個步驟。 重要的是,載入分析器、組裝專案、分析它、輸出報告並格式化它只需要十一行程式碼。
我們需要做的最後一件事是設定環境變量,我已經概述了一些提高其可讀性的方法。 為此,我們繼續: 參數 -> 新增參數 並加入三個變數:
您所要做的就是按下按鈕 跑 在右上角。 在組裝和分析該專案的同時,我將向您介紹該腳本。
直接編寫腳本
首先,我們要下載最新的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"
最後一步是在中顯示格式化的報告 標準輸出,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"
此時,專案的組裝和分析已經成功完成,我們可以進入選項卡 項目 и убедиться в этом。
現在我們點擊 檢查總數轉到查看分析器報告:
警告按診斷規則編號分組。 要瀏覽程式碼,您需要點擊帶有警告的行號。 點擊右上角的問號將開啟一個包含文件的新分頁。 您也可以透過點擊帶有分析器警告的行號來瀏覽程式碼。 使用時可以從遠端電腦進行導航 源樹根 標記。 對分析儀的這種操作模式感興趣的人可以熟悉相應的部分
查看分析儀的結果
現在我們已經完成了建置的部署和配置,讓我們來看看我們正在查看的專案中發現的一些有趣的警告。
警告 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;
}
分析器注意到一個錯誤,在動態分配記憶體後 創建對象,當異常發生時,記憶體沒有被清除,就會出現記憶體洩漏。
警告 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)
{
....
}
....
}
讓我們仔細看看。 表達 影像方向/8 將為假,如果 影像方向 範圍從-7到7。第二部分: (影像方向 / 8) != 3 檢查 影像方向 對於超出範圍:分別為從-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;
....
}
....
}
該程式碼片段很可能是透過反編譯獲得的。 然後,從留下的評論來看,部分不起作用的程式碼被刪除了。 然而,還剩下一些手術 遊標ID,這也沒有太大意義。
警告 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));
....
}
....
}
您可以一舉擺脫一行難以閱讀的程式碼,並透過檢查來解決問題 空指針。 我建議更改程式碼如下:
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();
}
}
該代碼看起來很奇怪。 在我看來,條件或重新分配變數時存在拼字錯誤 列標題按下目前狀態 意 假.
產量
正如我們所看到的,將 PVS-Studio 靜態分析器整合到您的 TeamCity 專案中非常簡單。 為此,只需編寫一個小設定檔就足夠了。 檢查程式碼將使您能夠在組裝後立即識別問題,這將有助於在更改的複雜性和成本仍然較低時消除問題。
如果您想與英語讀者分享這篇文章,請使用翻譯連結:Vladislav Stolyarov。
來源: www.habr.com