
Mēs turpinām padarīt PVS-Studio lietošanu ērtāku. Tagad mūsu analizators ir pieejams Chocolatey, pakotņu pārvaldniekā Windows. Mēs uzskatām, ka tas atvieglos PVS-Studio izvietošanu, it īpaši mākoņservisos. Lai tālu neietu, pārbaudīsim paša Chocolatey avota kodu. CI sistēma būs Azure DevOps.
Šeit ir saraksts ar citām mūsu rakstiem par integrāciju ar mākoņsistēmām:
Iesaku pievērst uzmanību pirmajam rakstam par integrāciju ar Azure DevOps, jo šajā gadījumā daži aspekti tika izlaisti, lai nerakstītu divreiz.
Tātad, šīs raksta varoņi:
— statiskās analīzes rīks, kas paredzēts kļūdu un potenciālo ievainojamību noteikšanai programmās, kas uzrakstītas valodās C, C++, C# un Java. Darbojas 64 bitu sistēmās Windows, Linux un macOS, un var analizēt kodu, kas paredzēts 32 bitu, 64 bitu un iebūvētiem ARM platformām. Ja jūs pirmo reizi izmēģināt statisko koda analīzi, lai pārbaudītu savus projektus, mēs iesakām iepazīties ar par to, kā ātri apskatīt interesantākos PVS-Studio brīdinājumus un novērtēt šī rīka iespējas.
— mākoņservisu komplekts, kas aptver visu izstrādes procesu. Šajā platformā ietilpst tādi rīki kā Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, kas ļauj paātrināt programmatūras izstrādes procesu un uzlabot tās kvalitāti.
— atvērtā koda pakotņu pārvaldnieks Windows. Projekta mērķis ir automatizēt visu programmatūras dzīves ciklu no instalēšanas līdz atjaunināšanai un dzēšanai Windows operētājsistēmās.
Par Chocolatey izmantošanu
Skatiet, kā instalēt pašu pakotņu pārvaldnieku, jūs varat šajā . Pilna dokumentācija par analizatora instalēšanu ir pieejama sadaļā "Instalācija, izmantojot pakotņu pārvaldnieku Chocolatey". Īsumā atkārtošu dažus tūrē.
Komanda, lai instalētu jaunāko analizatora versiju:
choco install pvs-studioKomanda, lai instalētu konkrētu PVS-Studio pakotnes versiju:
choco install pvs-studio --version=7.05.35617.2075Noklusējuma iestatījumi ir tikai analīzes motora komponents Core. Visus pārējos karogus (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) var nodot ar —package-parameters.
Piemērs komandas, kas instalēs analīzi ar paplašinājumu Visual Studio 2019:
choco install pvs-studio --package-parameters="'\/MSVS2019'"Tagad aplūkosim ērtas analīzes izmantošanas piemiru Azure DevOps.
Iestatījumi
Atgādinu, ka tādi jautājumi kā konta reģistrācija, Build Pipeline veidošana un konta sinhronizācija ar projektu, kas atrodas GitHub repozitorijā, ir atsevišķi. . Mūsu iestatīšana sāksies ar konfigurācijas faila rakstīšanu.
Sāksim ar palaišanas trigeru iestatīšanu, norādot, ka mēs uzsākam tikai izmaiņām. master lapu:
trigger:
- masterTālāk mums jāizvēlas virtuālā mašīna. Šobrīd tā būs Microsoft-hosted aģents ar Windows Server 2019 un Visual Studio 2019:
pool:
vmImage: 'windows-latest'Pāriesim pie konfigurācijas faila satura (bloks steps). Neskaitoties no tā, ka virtuālajā mašīnā nevar instalēt nejaušu programmatūru, es neveicu Docker konteineru pievienošanu. Mēs varam pievienot Chocolatey kā paplašinājumu Azure DevOps. Lai to izdarītu, pāriesim uz . Nospiedīsim Get it free. Pēc tam, ja esat jau autorizējies, vienkārši izvēlieties savu kontu, bet ja nē, tad veiciet to pašu pēc autorizācijas.

Šeit ir jāizvēlas, kur pievienosim paplašinājumu, un jānospiež poga Instalēt.

Pēc veiksmīgas instalācijas nospiedīsim Proceed to organization:

Tagad varam redzēt Chocolatey uzdevuma veidni konfigurācijas faila rediģēšanas logā uzdevumi azure-pipelines.yml: Nospiedīsim uz Chocolatey un redzēsim lauku sarakstu:

Šeit mums j選inās izvēlēties

komandu laukā. Laikā install Nuspec File Name norādīsim nepieciešamā pakotnes nosaukumu – pvs-studio. Ja versija netiks norādīta, tiks instalēta jaunākā, kas mums pilnībā apmierina. Nospiedīsim uz pogas un redzēsim izveidoto uzdevumu konfigurācijas failā. add steps: - task: ChocolateyCommand@0 inputs: command: 'install' installPackageId: 'pvs-studio'
Tālāk pāriesim pie mūsu faila galvenās daļas:- task: CmdLine@2 inputs: script:
Tagad mums jāizveido licencēšanas fails analīzei. Šeit PVSNAME PVSKEY un – ir mainīgo nosaukumi, kuru vērtības mēs norādām iestatījumos. Tie glabās PVS-Studio pieteikšanās un licenci. Lai iestatītu to vērtības, atvērsim izvēlni Variables->New variable . Izveidosim mainīgospieteikšanās un PVSKEY lai pieteiktos un – ir mainīgo nosaukumi, kuru vērtības mēs norādām iestatījumos. Tie glabās PVS-Studio pieteikšanās un licenci. Lai iestatītu to vērtības, atvērsim izvēlni analizatora atslēgai. Neaizmirstiet atzīmēt rūtiņu Saglabājiet šo vērtību noslēpumā lai – ir mainīgo nosaukumi, kuru vērtības mēs norādām iestatījumos. Tie glabās PVS-Studio pieteikšanās un licenci. Lai iestatītu to vērtības, atvērsim izvēlni. Komandu kods:
saukt "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" akreditācijas
–u $(PVSNAME) –n $(PVSKEY)Sagatavosim projektu ar bat-failu, kas atrodas repozitorijā:
saukt build.batIzveidosim mapi, kurā tiks saglabāti analizatora darba rezultātu faili:
saukt mkdir PVSTestResultsUzsāksim projekta analīzi:
saukt "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog Konvertēsim mūsu ziņojumu uz html formātu, izmantojot PlogConverter utilītu:
saukt "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o PVSTestResults .PVSTestResultsChoco.plogTagad ir jāizveido uzdevums, lai varētu eksportēt ziņojumu.
- uzdevums: PublishBuildArtifacts@1
ievadi:
ceļšUzPublicēšanu: PVSTestResults
artefaktaNosaukums: PVSTestResults
nosacījums: vienmēr()Pilns konfigurācijas fails izskatās šādi:
triggers:
- master
pool:
vmImage: 'windows-latest'
solis:
- uzdevums: ChocolateyCommand@0
ievadi:
komanda: 'install'
instalētPakasId: 'pvs-studio'
- uzdevums: CmdLine@2
ievadi:
skripts: |
saukt "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
akreditācijas –u $(PVSNAME) –n $(PVSKEY)
saukt build.bat
saukt mkdir PVSTestResults
saukt "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
saukt "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o .PVSTestResults .PVSTestResultsChoco.plog
- uzdevums: PublishBuildArtifacts@1
ievadi:
ceļšUzPublicēšanu: PVSTestResults
artefaktaNosaukums: PVSTestResults
nosacījums: vienmēr()Noklikšķināsim Saglabāt->Saglabāt->Palaist uzdevuma palaišanai. Eksportēsim ziņojumu, ieejot uzdevumu cilnē.
Chocolatey projekts satur kopumā 37615 rindas C# koda. Apskatīsim dažas no atrastajām kļūdām.
Pārbaudes rezultāti
Brīdinājums N1
Analizatora brīdinājums: ‘Provider’ mainīgais tiek piešķirts pats sev. CrytpoHashProviderSpecs.cs 38
public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
....
protected CryptoHashProvider Provider;
....
public override void Context()
{
Provider = Provider = new CryptoHashProvider(FileSystem.Object);
}
}Analizators atklāja, ka mainīgais tiek piešķirts pats sev, kas nav jēgpilni. Visticamāk, kādā no šiem mainīgajiem vajadzētu būt citam mainīgajam. Vai nu tas ir drukas kļūda, un liekā piešķiršana vienkārši jāizdzēš.
Brīdinājums N2
Analizatora brīdinājums: [CWE-480] Operators ‘&’ novērtē abus operandus. Varbūt labāk izmantot īso shēmas operatoru ‘&&’. Platform.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;
}
}Atšķirība starp operatoru & un operatoru && ir tajā, ka, ja kreisā izteiksmes daļa — false, tomēr tiks aprēķināta labā puse, kas šajā gadījumā nozīmē liekas metodes izsaukumus system.directory_exists.
Apskatītajā fragmentā tas ir neliels pārkāpums. Jā, šo nosacījumu var optimizēt, aizstājot operatoru & ar operatoru &&, bet praktiskā ziņā tam nav nekādas ietekmes. Tomēr citos gadījumos sajaukšana starp & un && var radīt nopietnas problēmas, kad labā puse izteiksmē strādā ar nederīgiem/vai nepieņemamiem vērtībām. Piemēram, mūsu kļūdu kolekcijā, , ir šāds gadījums:
if ((k < nct) & (s[k] != 0.0))Pat ja indekss k ir nederīgs, tas tiks izmantots, lai piekļūtu masīva elementam. Rezultātā tiks ģenerēta izņēmuma IndexOutOfRangeException.
Brīdinājumi N3, N4
Analizatora brīdinājums: [CWE-571] Izteiksme ‘shortPrompt’ vienmēr ir patiess. InteractivePrompt.cs 101
Analizatora brīdinājums: [CWE-571] Izteiksme ‘shortPrompt’ vienmēr ir patiess. InteractivePrompt.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
....
}
....
}Šajā gadījumā ir dīvaina loģika ternārajam operatoram. Paskatīsimies detalizētāk: ja izpildīsies nosacījums, ko es esmu atzīmējis ar numuru 1, tad mēs pāriesim pie nosacījuma 2, kas vienmēr true, tādējādi izpildīsies rinda 3. Ja, tomēr, nosacījums 1 izrādīsies nepaties, tad mēs pāriesim uz rindu, ko esmu atzīmējis ar numuru 4, kur nosacījums arī vienmēr true, tādējādi izpildīsies rinda 5. Tādējādi nosacījumi, kuriem ir komentārs 0, nekad netiks izpildīti, kas var būt ne gluži tā loģika, uz kuru programmētājs cerēja.
Brīdinājums N5
Analizatora brīdinājums: [CWE-783] Iespējams, ka ‘?:’ operators darbojas citādāk, nekā gaidīts. Tā prioritāte ir zemāka nekā citu operatoru prioritāte tā nosacījumā. Options.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);
}
}Diagnostika aktivizējās uz rindu:
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)Tā kā mainīgais j Dažās rindiņās augstāk tiek inicializēts ar nulli, ternārais operators atgriezīs vērtību false. Šī nosacījuma dēļ cikla ķermenis tiks izpildīts tikai vienu reizi. Man šķiet, ka šis koda fragments darbojas pavisam citādāk, nekā iecerējis programmētājs.
Brīdinājums N6
Analizatora brīdinājums: [CWE-571] Izteiksme 'installedPackageVersions.Count != 1' vienmēr ir patiesa. NugetService.cs 1405
private void remove_nuget_cache_for_package(....)
{
if (!config.AllVersions && installedPackageVersions.Count > 1)
{
const string allVersionsChoice = "Visas versijas";
if (installedPackageVersions.Count != 1)
{
choices.Add(allVersionsChoice);
}
....
}
....
}Šeit ir dīvains iemontēts nosacījums: installedPackageVersions.Count != 1, kas vienmēr būs true. Bieži šāds brīdinājums norāda uz loģisku kļūdu kodā, bet citos gadījumos tas vienkārši norāda uz lieku pārbaudi.
Brīdinājums N7
Analizatora brīdinājums: Bieži sastopami apakšizteikumi 'commandArguments.contains("-apikey")' ir gan pa kreisi, gan pa labi no operatora '||'. 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");
}Programmētājs, kurš uzrakstījis šo koda daļu, nokopēja divas pēdējās rindiņas un aizmirsās tās rediģēt. Tādēļ Chocolatey lietotājiem tika izslēgta iespēja izmantot parametrus apikey vēl ar dažiem citiem veidiem. Līdzīgi iepriekš minētajiem parametriem, varu ieteikt šādus variantus:
commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");Kopēšanas un ievietošanas kļūdas ir liela iespēja agrāk vai vēlāk parādīties jebkurā projektā ar lielu avota kodu daudzumu, un viens no labākajiem veidiem, kā ar tām cīnīties, ir statiskā analīze.
P.S. Un, kā vienmēr, šī kļūda bieži parādās daudzrindā nosacījuma beigās :). Skatiet publikāciju "".
Brīdinājums N8
Analizatora brīdinājums: [CWE-476] 'installedPackage' objekts tika izmantots pirms tā pārbaudīšanas pret nulli. Pārbaudiet rindas: 910, 917. NugetService.cs 910
public virtual ConcurrentDictionary 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)
{
....
}
....
}Klasiskā kļūda: vispirms objekts installedPackage tiek izmantots, un pēc tam pārbauda uz null. Šī diagnostika norāda uz vienu no divām problēmām programmā: vai nu installedPackage nekad nav vienāds null, kas ir apšaubāms, un tad pārbaude ir lieka, vai mēs potenciāli varam iegūt nopietnu kļūdu kodā – mēģinājumu piekļūt nulles atsaucei.
Secinājums
Mēs esam veikuši vēl vienu mazu soli – tagad izmantot PVS-Studio ir kļuvusi vēl vienkāršāka un ērta. Tāpat vēlos teikt, ka Chocolatey ir labs pakotņu menedžeris ar niecīgiem koda trūkumiem, kurus varētu būt vēl mazāk, izmantojot PVS-Studio.
Aicinas un izmēģināt PVS-Studio. Regulāra statiskā analizatora lietošana paaugstinās jūsu komandas izstrādātā koda kvalitāti un uzticamību un palīdzēs novērst daudzas .
P.S.
Pirms publikācijas mēs nosūtījām rakstu Chocolatey izstrādātājiem, un viņi to labi pieņēma. Neko kritisku mēs neatradām, taču viņiem, piemēram, patika mūsu atrasta kļūda, kas saistīta ar atslēgu „api-key”.
Ja vēlaties dalīties šajā rakstā ar angliski runājošo auditoriju, lūdzu, izmantojiet saiti uz tulkojumu: Vladislav Stolyarov. .
Avots: habr.com
