ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а
Настављамо да чинимо коришћење ПВС-Студио практичнијим. Наш анализатор је сада доступан у Цхоцолатеи-у, менаџеру пакета за Виндовс. Верујемо да ће ово олакшати примену ПВС-Студио, посебно у цлоуд сервисима. Да не бисмо ишли далеко, хајде да проверимо изворни код исте Чоколаде. Азуре ДевОпс ће деловати као ЦИ систем.

Ево листе наших других чланака на тему интеграције са клауд системима:

Саветујем вам да обратите пажњу на први чланак о интеграцији са Азуре ДевОпс-ом, пошто су у овом случају неке тачке изостављене да се не би дуплирале.

Дакле, хероји овог чланка:

ПВС-Студио је статичка алатка за анализу кода дизајнирана да идентификује грешке и потенцијалне рањивости у програмима написаним на Ц, Ц++, Ц# и Јави. Ради на 64-битним Виндовс, Линук и мацОС системима и може анализирати код дизајниран за 32-битне, 64-битне и уграђене АРМ платформе. Ако вам је ово први пут да покушавате статичку анализу кода да бисте проверили своје пројекте, препоручујемо вам да се упознате чланак о томе како да брзо погледате најзанимљивија упозорења ПВС-Студио и процените могућности овог алата.

Азуре ДевОпс — скуп сервиса у облаку који заједно покривају цео процес развоја. Ова платформа укључује алате као што су Азуре Пипелинес, Азуре Боардс, Азуре Артифацтс, Азуре Репос, Азуре Тест Планс, који вам омогућавају да убрзате процес креирања софтвера и побољшате његов квалитет.

Цхоцолатеи је менаџер пакета отвореног кода за Виндовс. Циљ пројекта је аутоматизација целокупног животног циклуса софтвера од инсталације до ажурирања и деинсталације на Виндовс оперативним системима.

О коришћењу чоколаде

Овде можете видети како да инсталирате сам менаџер пакета веза. Комплетна документација за уградњу анализатора доступна је на адреси веза Погледајте одељак Инсталација помоћу менаџера пакета Цхоцолатеи. Укратко ћу поновити неке тачке одатле.

Команда за инсталирање најновије верзије анализатора:

choco install pvs-studio

Команда за инсталирање одређене верзије пакета ПВС-Студио:

choco install pvs-studio --version=7.05.35617.2075

Подразумевано је инсталирано само језгро анализатора, компонента Цоре. Све остале заставице (Стандалоне, ЈаваЦоре, ИДЕА, МСВС2010, МСВС2012, МСВС2013, МСВС2015, МСВС2017, МСВС2019) могу се пренети помоћу --пацкаге-параметерс.

Пример команде која ће инсталирати анализатор са додатком за Висуал Студио 2019:

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

Погледајмо сада пример погодне употребе анализатора под Азуре ДевОпс-ом.

подешавање

Дозволите ми да вас подсетим да постоји посебан одељак о таквим питањима као што су регистрација налога, креирање буилд Пипелине-а и синхронизација вашег налога са пројектом који се налази у ГитХуб репозиторијуму. чланак. Наше подешавање ће одмах почети писањем конфигурационе датотеке.

Прво, подесимо покретач покретања, који означава да покрећемо само за промене у мајстор грана:

trigger:
- master

Затим морамо да изаберемо виртуелну машину. За сада ће то бити агент који хостује Мицрософт са Виндовс Сервер 2019 и Висуал Студио 2019:

pool:
  vmImage: 'windows-latest'

Пређимо на тело конфигурационе датотеке (блок кораци). Упркос чињеници да не можете инсталирати произвољан софтвер у виртуелну машину, нисам додао Доцкер контејнер. Можемо додати Цхоцолатеи као проширење за Азуре ДевОпс. Да бисмо то урадили, идемо на веза. Кликните Ослободите га. Затим, ако сте већ овлашћени, једноставно изаберите свој налог, а ако нисте, урадите исто након ауторизације.

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Овде треба да изаберете где ћемо додати проширење и кликните на дугме Инсталирати.

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Након успешне инсталације, кликните Пређите на организацију:

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Сада можете да видите шаблон за задатак Чоколада у прозору задаци приликом уређивања конфигурационе датотеке азуре-пипелинес.имл:

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Кликните на Цхоцолатеи и погледајте листу поља:

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Овде треба да изаберемо инсталирати на терену са екипама. ИН Нуспец Име датотеке наведите назив потребног пакета – пвс-студио. Ако не наведете верзију, биће инсталирана најновија, што нам у потпуности одговара. Хајде да притиснемо дугме додати и видећемо генерисани задатак у конфигурационој датотеци.

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

Затим, пређимо на главни део наше датотеке:

- task: CmdLine@2
  inputs:
    script: 

Сада треба да креирамо датотеку са лиценцом анализатора. Ево ПВСНАМЕ и ПВСКЕИ – имена променљивих чије вредности наводимо у подешавањима. Они ће чувати ПВС-Студио логин и лиценцни кључ. Да бисте подесили њихове вредности, отворите мени Променљиве->Нова променљива. Хајде да креирамо променљиве ПВСНАМЕ за пријаву и ПВСКЕИ за кључ анализатора. Не заборавите да означите поље Чувајте ову вредност у тајности за ПВСКЕИ. Код команде:

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

Хајде да направимо пројекат користећи бат датотеку која се налази у спремишту:

сall build.bat

Хајде да направимо фасциклу у којој ће се чувати датотеке са резултатима анализатора:

сall mkdir PVSTestResults

Почнимо са анализом пројекта:

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

Конвертујемо наш извештај у хтмл формат помоћу услужног програма ПлогСонвертер:

с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()

Хајде да кликнемо Сачувај->Сачувај->Покрени да покрене задатак. Хајде да преузмемо извештај тако што ћемо отићи на картицу задаци.

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Пројекат Цхоцолатеи садржи само 37615 линија Ц# кода. Погледајмо неке од пронађених грешака.

Резултати теста

Упозорење Н1

Упозорење анализатора: ВКСНУМКС Променљива 'Провидер' је додељена самој себи. ЦритпоХасхПровидерСпецс.цс 38

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

Анализатор је открио додељивање променљиве себи, што нема смисла. Највероватније би уместо једне од ових варијабли требало да стоји нека друга. Па, или је ово грешка у куцању, а додатни задатак се једноставно може уклонити.

Упозорење Н2

Упозорење анализатора: ВКСНУМКС [ЦВЕ-480] Оператор '&' процењује оба операнда. Можда би уместо тога требало користити оператор кратког споја '&&'. Платформ.цс 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;
  }
}

Разлика оператера & од оператера && је да ако је лева страна израза лажан, онда ће се десна страна ипак израчунати, што у овом случају подразумева непотребне позиве метода систем.дирецтори_екистс.

У разматраном фрагменту ово је мањи недостатак. Да, овај услов се може оптимизовати заменом оператора & са оператором &&, али са практичне тачке гледишта, то не утиче ни на шта. Међутим, у другим случајевима, конфузија између & и && може изазвати озбиљне проблеме када се десна страна израза третира са нетачним/неважећим вредностима. На пример, у нашој колекцији грешака, идентификован помоћу В3093 дијагностике, постоји овај случај:

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

Чак и ако индекс k је нетачан, користиће се за приступ елементу низа. Као резултат, биће избачен изузетак ИндекОутОфРангеЕкцептион.

Упозорења Н3, Н4

Упозорење анализатора: ВКСНУМКС [ЦВЕ-571] Израз 'схортПромпт' је увек тачан. ИнтерацтивеПромпт.цс 101
Упозорење анализатора: ВКСНУМКС [ЦВЕ-571] Израз 'схортПромпт' је увек тачан. ИнтерацтивеПромпт.цс 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 никада неће бити испуњени, што можда није баш логика рада коју је програмер очекивао.

Упозорење Н5

Упозорење анализатора: ВКСНУМКС [ЦВЕ-783] Можда оператор '?:' ради на другачији начин него што се очекивало. Његов приоритет је нижи од приоритета других оператера у његовом стању. Оптионс.цс 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 неколико редова изнад је иницијализовано на нулу, тернарни оператор ће вратити вредност лажан. Због овог услова, тело петље ће бити извршено само једном. Чини ми се да овај део кода уопште не функционише онако како је програмер намеравао.

Упозорење Н6

Упозорење анализатора: ВКСНУМКС [ЦВЕ-571] Израз 'инсталледПацкагеВерсионс.Цоунт != 1' је увек тачан. НугетСервице.цс 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);
    }
    ....
  }
  ....
}

Овде постоји чудан угнежђени услов: ИнсталледПацкагеВерсионс.Цоунт != 1који ће увек бити прави. Често такво упозорење указује на логичку грешку у коду, ау другим случајевима једноставно указује на сувишну проверу.

Упозорење Н7

Упозорење анализатора: ВКСНУМКС Постоје идентични подизрази 'цоммандАргументс.цонтаинс("-апикеи")' лево и десно од '||' оператер. АргументсУтилити.цс 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");
}

Програмер који је написао овај део кода је копирао и налепио последња два реда и заборавио да их уреди. Због тога корисници Цхоцолатеи-а нису могли да примене параметар апикеи још пар начина. Слично горе наведеним параметрима, могу да понудим следеће опције:

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

Грешке при копирању и лепљењу имају велике шансе да се појаве пре или касније у било ком пројекту са великом количином изворног кода, а један од најбољих алата за борбу против њих је статичка анализа.

ПС И као и увек, ова грешка има тенденцију да се појави на крају вишелинијског услова :). Погледајте публикацију "Ефекат последње линије".

Упозорење Н8

Упозорење анализатора: ВКСНУМКС [ЦВЕ-476] Објект 'инсталледПацкаге' је коришћен пре него што је верификован у односу на нулл. Контролне линије: 910, 917. НугетСервице.цс 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)
  {
    ....
  }
  ....
}

Класична грешка: прво објекат ИнсталледПацкаге се користи, а затим се проверава нула. Ова дијагностика нам говори о једном од два проблема у програму: било који ИнсталледПацкаге никад једнака нула, што је сумњиво, а онда је провера сувишна или бисмо потенцијално могли да добијемо озбиљну грешку у коду – покушај приступа нултој референци.

Закључак

Дакле, направили смо још један мали корак - сада је коришћење ПВС-Студио постало још лакше и практичније. Такође бих желео да кажем да је Цхоцолатеи добар менаџер пакета са малим бројем грешака у коду, којих би могло бити и мање када користите ПВС-Студио.

позивамо вас преузети и испробајте ПВС-Студио. Редовна употреба статичког анализатора ће побољшати квалитет и поузданост кода који ваш тим развија и помоћи ће у спречавању многих рањивости нултог дана.

ПС

Пре објављивања, послали смо чланак Цхоцолатеи програмерима и они су га добро примили. Нисмо нашли ништа критично, али њима се, на пример, допала грешка коју смо пронашли у вези са кључем „апи-кеи“.

ПВС-Студио је сада у Цхоцолатеи-у: проверава Цхоцолатеи испод Азуре ДевОпс-а

Ако желите да поделите овај чланак са публиком која говори енглески, користите линк за превод: Владислав Столиаров. ПВС-Студио је сада у Цхоцолатеи-у: Проверавам Цхоцолатеи под Азуре ДевОпс-ом.

Извор: ввв.хабр.цом

Додај коментар