PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey
我們不斷地讓 PVS-Studio 的使用變得更方便。 我們的分析器現在可以在 Chocolatey(Windows 的套件管理器)中使用。 我們相信這將促進PVS-Studio的部署,特別是在雲端服務。 為了不走太遠,讓我們檢查一下同一個 Chocolatey 的源代碼。 Azure DevOps 將充當 CI 系統。

以下是我們關於與雲端系統整合主題的其他文章的清單:

我建議您注意第一篇關於與 Azure DevOps 整合的文章,因為在這種情況下省略了一些要點,以免重複。

那麼,本文的主角:

PVS工作室 是一種靜態程式碼分析工具,旨在識別用 C、C++、C# 和 Java 編寫的程式中的錯誤和潛在漏洞。 在 64 位元 Windows、Linux 和 macOS 系統上運行,可以分析為 32 位元、64 位元和嵌入式 ARM 平台設計的程式碼。 如果這是您第一次嘗試靜態程式碼分析來檢查您的項目,我們建議您熟悉一下 文章 關於如何快速查看最有趣的 PVS-Studio 警告並評估該工具的功能。

Azure開發運營 ——一套共同涵蓋整個開發流程的雲端服務。 該平台包括Azure Pipelines、Azure Boards、Azure Artifacts、Azure Repos、Azure Test Plans等工具,可讓您加快軟體建立流程並提高其品質。

巧克力味 是 Windows 的開源套件管理器。 該專案的目標是自動化 Windows 作業系統上從安裝到更新和卸載的整個軟體生命週期。

關於使用 Chocolatey

您可以在此處查看如何安裝套件管理器本身 鏈接。 有關安裝分析儀的完整文檔,請造訪: 鏈接 請參閱使用 Chocolatey 套件管理器進行安裝部分。 我將簡要重複其中的一些要點。

安裝最新版本分析器的命令:

choco install pvs-studio

安裝特定版本的 PVS-Studio 軟體包的命令:

choco install pvs-studio --version=7.05.35617.2075

預設情況下,僅安裝分析器的核心,即 Core 元件。 所有其他標誌(Standalone、JavaCore、IDEA、MSVS2010、MSVS2012、MSVS2013、MSVS2015、MSVS2017、MSVS2019)都可以使用 --package-parameters 傳遞。

將使用 Visual Studio 2019 外掛程式安裝分析器的命令範例:

choco install pvs-studio --package-parameters="'/MSVS2019'"

現在讓我們來看看在Azure DevOps下方便使用分析器的範例。

調整

讓我提醒您,有一個單獨的部分介紹註冊帳戶、建立建置管道以及將您的帳戶與 GitHub 儲存庫中的專案同步等問題。 文章。 我們的設定將立即開始編寫設定檔。

首先,讓我們設定一個啟動觸發器,表示我們僅針對以下內容的變更啟動 分支:

trigger:
- master

接下來我們需要選擇一個虛擬機器。 目前,它將是 Microsoft 託管的 Windows Server 2019 和 Visual Studio 2019 代理程式:

pool:
  vmImage: 'windows-latest'

讓我們繼續討論設定檔的主體(區塊 步驟)。 儘管你不能在虛擬機器中安裝任意軟體,但我沒有添加 Docker 容器。 我們可以新增 Chocolatey 作為 Azure DevOps 的擴充。 為此,讓我們轉到 鏈接。 點選 免費獲取。 接下來,如果您已經獲得授權,則只需選擇您的帳戶即可,如果沒有,則授權後執行相同的操作。

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

在這裡您需要選擇我們將新增擴充功能的位置,然後按一下按鈕 安裝.

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

安裝成功後,點選 繼續組織:

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

現在您可以在視窗中看到 Chocolatey 任務的模板 任務 編輯設定檔時 天藍色管道.yml:

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

點擊 Chocolatey 並查看字段列表:

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

這裡我們需要選擇 安裝 與球隊一起在球場上。 在 Nuspec 檔案名稱 指示所需包的名稱 - pvs-studio。 如果不指定版本,則會安裝最新版本,這完全適合我們。 讓我們按下按鈕 添加 我們將在設定檔中看到生成的任務。

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

接下來,讓我們繼續討論文件的主要部分:

- task: CmdLine@2
  inputs:
    script: 

現在我們需要使用分析器許可證來建立一個文件。 這裡 PVS名稱 и PVSKEY – 我們在設定中指定其值的變數名稱。 他們將儲存 PVS-Studio 登入名稱和許可證密鑰。 要設定它們的值,請打開選單 變數->新變數。 讓我們創建變數 PVS名稱 用於登入和 PVSKEY 為分析儀鍵。 不要忘記選中該框 將此值保密 PVSKEY。 命令代碼:

сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials 
–u $(PVSNAME) –n $(PVSKEY)

讓我們使用儲存庫中的 bat 檔案建置專案:

сall build.bat

讓我們建立一個資料夾,用於儲存包含分析器結果的檔案:

сall mkdir PVSTestResults

讓我們開始分析該項目:

сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog 

我們使用 PlogСonverter 實用程式將報表轉換為 html 格式:

сall "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
–t html –o PVSTestResults .PVSTestResultsChoco.plog

現在您需要建立一個任務以便上傳報告。

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

完整的設定檔如下所示:

trigger:
- master

pool:
  vmImage: 'windows-latest'

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

- task: CmdLine@2
  inputs:
    script: |
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      credentials –u $(PVSNAME) –n $(PVSKEY)
      call build.bat
      call mkdir PVSTestResults
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      –t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
      call "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
      –t html –o .PVSTestResults .PVSTestResultsChoco.plog

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

我們點擊一下 保存->保存->運行 運行任務。 讓我們轉到任務標籤來下載報告。

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

Chocolatey 專案僅包含 37615 行 C# 程式碼。 讓我們看看發現的一些錯誤。

檢測結果

警告 N1

分析儀警告: V3005 “Provider”變數被分配給它自己。 CrytpoHashProviderSpecs.cs 38

public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
  ....
  protected CryptoHashProvider Provider;
  ....
  public override void Context()
  {
    Provider = Provider = new CryptoHashProvider(FileSystem.Object);
  }
}

分析器偵測到變數對其自身的賦值,這是沒有意義的。 最有可能的是,應該用其他變數來取代其中一個變數。 好吧,或者這是一個拼字錯誤,並且可以簡單地刪除額外的分配。

警告 N2

分析儀警告: V3093 [CWE-480] '&' 運算子計算兩個運算元。 也許應該使用短路“&&”運算符。 平台.cs 64

public static PlatformType get_platform()
{
  switch (Environment.OSVersion.Platform)
  {
    case PlatformID.MacOSX:
    {
      ....
    }
    case PlatformID.Unix:
    if(file_system.directory_exists("/Applications")
      & file_system.directory_exists("/System")
      & file_system.directory_exists("/Users")
      & file_system.directory_exists("/Volumes"))
      {
        return PlatformType.Mac;
      }
        else
          return PlatformType.Linux;
    default:
      return PlatformType.Windows;
  }
}

營運商差異 & 來自營運商 && 如果表達式的左邊是 ,那麼右側仍然會被計算,在這種情況下這意味著不必要的方法調用 系統目錄存在.

在所考慮的片段中,這是一個小缺陷。 是的,可以透過將 & 運算子替換為 && 運算子來優化此條件,但從實際角度來看,這不會產生任何影響。 但是,在其他情況下,當表達式的右側使用不正確/無效的值時,& 和 && 之間的混淆可能會導致嚴重的問題。 例如,在我們的錯誤集合中, 使用 V3093 診斷識別,有這樣的情況:

if ((k < nct) & (s[k] != 0.0))

即使指數 k 不正確,它將用於存取數組元素。 結果會拋出例外 索引超出範圍異常.

警告 N3、N4

分析儀警告: V3022 [CWE-571] 表達式「shortPrompt」始終為 true。 互動式提示.cs 101
分析儀警告: V3022 [CWE-571] 表達式「shortPrompt」始終為 true。 互動式提示.cs 105

public static string 
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
  ....
  if (shortPrompt)
  {
    var choicePrompt = choice.is_equal_to(defaultChoice) //1
    ?
    shortPrompt //2
    ?
    "[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), //3
    choice.Substring(1,choice.Length - 1))
    :
    "[{0}]".format_with(choice.ToUpperInvariant()) //0
    : 
    shortPrompt //4
    ? 
    "[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), //5
    choice.Substring(1,choice.Length - 1)) 
    :
    choice; //0
    ....
  }
  ....
}

在這種情況下,三元運算子的運算背後有一個奇怪的邏輯。 讓我們仔細看看:如果滿足我用數字 1 標記的條件,那麼我們將繼續執行條件 2,該條件始終是 ,這意味著第 3 行將被執行。如果條件 1 結果為假,那麼我們將轉到標有數字 4 的行,其中的條件也始終為 ,這意味著將執行第5行。因此,註解0標記的條件永遠不會被滿足,這可能不完全是程式設計師期望的操作邏輯。

警告 N5

分析儀警告: V3123 [CWE-783] 也許「?:」運算子的工作方式與預期不同。 其優先順序低於該條件下其他業者的優先順序。 選項.cs 1019

private static string GetArgumentName (...., string description)
{
  string[] nameStart;
  if (maxIndex == 1)
  {
    nameStart = new string[]{"{0:", "{"};
  }
  else
  {
    nameStart = new string[]{"{" + index + ":"};
  }
  for (int i = 0; i < nameStart.Length; ++i) 
  {
    int start, j = 0;
    do 
    {
      start = description.IndexOf (nameStart [i], j);
    } 
    while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
    ....
    return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
  }
}

診斷適用於此線路:

while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)

由於變數 j 上面幾行初始化為零,三元運算子將傳回值 。 由於這種情況,循環體將僅執行一次。 在我看來,這段程式碼根本沒有按照程式設計師的意圖運作。

警告 N6

分析儀警告: V3022 [CWE-571] 表達式「installedPackageVersions.Count != 1」始終為 true。 NugetService.cs 1405

private void remove_nuget_cache_for_package(....)
{
  if (!config.AllVersions && installedPackageVersions.Count > 1)
  {
    const string allVersionsChoice = "All versions";
    if (installedPackageVersions.Count != 1)
    {
      choices.Add(allVersionsChoice);
    }
    ....
  }
  ....
}

這裡有一個奇怪的嵌套條件: 安裝的PackageVersions.Count != 1這將永遠是 。 通常,此類警告表示程式碼中存在邏輯錯誤,而在其他情況下,它僅表示冗餘檢查。

警告 N7

分析儀警告: V3001 '||' 的左邊和右側有相同的子表達式 'commandArguments.contains("-apikey")' 操作員。 ArgumentsUtility.cs 42

public static bool arguments_contain_sensitive_information(string
 commandArguments)
{
  return commandArguments.contains("-install-arguments-sensitive")
  || commandArguments.contains("-package-parameters-sensitive")
  || commandArguments.contains("apikey ")
  || commandArguments.contains("config ")
  || commandArguments.contains("push ")
  || commandArguments.contains("-p ")
  || commandArguments.contains("-p=")
  || commandArguments.contains("-password")
  || commandArguments.contains("-cp ")
  || commandArguments.contains("-cp=")
  || commandArguments.contains("-certpassword")
  || commandArguments.contains("-k ")
  || commandArguments.contains("-k=")
  || commandArguments.contains("-key ")
  || commandArguments.contains("-key=")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key");
}

編寫這段程式碼的程式設計師複製並貼上了最後兩行,但忘記編輯它們。 因此,Chocolatey 使用者無法套用該參數 apikey 還有幾種方法。 與上面的參數類似,我可以提供以下選項:

commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");

在任何具有大量原始程式碼的專案中,複製貼上錯誤遲早都會出現,而解決這些錯誤的最佳工具之一就是靜態分析。

PS 與往常一樣,此錯誤往往出現在多行條件的末尾:)。 參見出版品“最後一行效果".

警告 N8

分析儀警告: V3095 [CWE-476] 在驗證「installedPackage」物件是否為 null 之前,已使用該物件。 檢查行:910、917。NugetService.cs 910

public virtual ConcurrentDictionary<string, PackageResult> get_outdated(....)
{
  ....
  var pinnedPackageResult = outdatedPackages.GetOrAdd(
    packageName, 
    new PackageResult(installedPackage, 
                      _fileSystem.combine_paths(
                        ApplicationParameters.PackagesLocation, 
                        installedPackage.Id)));
  ....
  if (   installedPackage != null
      && !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion) 
      && !config.UpgradeCommand.ExcludePrerelease)
  {
    ....
  }
  ....
}

經典錯誤:物件優先 已安裝的套件 使用然後檢查 。 此診斷告訴我們程序中的兩個問題之一: 已安裝的套件 永遠不平等 ,這是值得懷疑的,然後檢查是多餘的,或者我們可能會在程式碼中遇到嚴重錯誤 - 嘗試存取空引用。

結論

所以我們又邁出了一小步 - 現在使用 PVS-Studio 變得更加容易和方便。 我還想說,Chocolatey 是一個很好的套件管理器,程式碼中的錯誤很少,使用 PVS-Studio 時錯誤可能會更少。

我們邀請您 下載 並嘗試PVS-Studio。 定期使用靜態分析器將提高您的團隊開發的程式碼的品質和可靠性,並有助於防止許多問題 零日漏洞.

聚苯乙烯

在發表之前,我們將這篇文章發送給了 Chocolatey 開發人員,他們收到了很好的回饋。 我們沒有發現任何關鍵的東西,但例如,他們喜歡我們發現的與「api-key」金鑰相關的錯誤。

PVS-Studio 現在位於 Chocolatey 中:從 Azure DevOps 下檢查 Chocolatey

如果您想與英語讀者分享這篇文章,請使用翻譯連結:Vladislav Stolyarov。 PVS-Studio 現已加入 Chocolatey:在 Azure DevOps 下檢查 Chocolatey.

來源: www.habr.com

添加評論