Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Travis CI ass e verdeelt Webservice fir Software ze bauen an ze testen déi GitHub als Quellcode-Hosting benotzt. Zousätzlech zu den uewe genannte Betriebsszenarien, kënnt Dir Är eege bäidroen duerch déi extensiv Konfiguratiounsoptiounen. An dësem Artikel wäerte mir den Travis CI konfiguréieren fir mat PVS-Studio mat dem PPSSPP Code Beispill ze schaffen.

Aféierung

Travis C.I. ass e Webservice fir Software ze bauen an ze testen. Et gëtt normalerweis a Verbindung mat kontinuéierlechen Integratiounspraktiken benotzt.

PPSSPP - PSP Spillkonsolemulator. De Programm ass fäeg de Start vun all Spiller vun Disk-Biller ze emuléieren, déi fir Sony PSP geduecht sinn. De Programm gouf den 1. November 2012 verëffentlecht. PPSSPP ass lizenzéiert ënner GPL v2. Jidderee kann Verbesserunge maachen Projet Quellcode.

PVS-Studio - e statesche Code Analyser fir no Feeler a potenziell Schwachstelle am Programmcode ze sichen. An dësem Artikel, fir eng Verännerung, lancéiere mir PVS-Studio net lokal op der Maschinn vum Entwéckler, mee an der Wollek, a kuckt no Feeler am PPSSPP.

Ariichten Travis CI

Mir brauchen e Repository op GitHub, wou de Projet dee mir brauchen ass lokaliséiert, souwéi e Schlëssel fir PVS-Studio (Dir kënnt kréien Prozess Schlëssel oder gratis fir Open Source Projeten).

Loosst eis op de Site goen Travis C.I.. No Autorisatioun mat Ärem GitHub Kont, gesi mir eng Lëscht vu Repositories:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Fir den Test hunn ech PPSSPP geflunn.

Mir aktivéieren de Repository dee mir wëllen sammelen:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Am Moment kann den Travis CI eise Projet net bauen, well et keng Instruktioune gëtt fir ze bauen. Also ass et Zäit fir d'Konfiguratioun.

Während der Analyse wäerten e puer Verännerlechen nëtzlech sinn fir eis, zum Beispill de Schlëssel fir PVS-Studio, wat onerwënscht wier an der Konfiguratiounsdatei ze spezifizéieren. Also loosst eis Ëmfeldvariablen addéieren mat de Build-Astellungen am Travis CI:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Mir brauchen:

  • PVS_USERNAME - Benotzernumm
  • PVS_KEY - Schlëssel
  • MAIL_USER - E-Mail déi benotzt gëtt fir de Bericht ze schécken
  • MAIL_PASSWORD - E-Mail Passwuert

Déi lescht zwee sinn fakultativ. Dës gi benotzt fir Resultater per Mail ze schécken. Wann Dir de Rapport op eng aner Manéier wëllt verdeelen, musst Dir se net uginn.

Also, mir hunn d'Ëmweltvariablen bäigefüügt déi mir brauchen:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Loosst eis elo eng Datei erstellen .travis.yml a Plaz et an der Wuerzel vum Projet. PPSSPP hat schonn e Configuratiounsdatei fir Travis CI, awer et war ze grouss a komplett net gëeegent fir d'Beispill, also hu mir et vill vereinfachen an nëmmen d'Basiselementer verloossen.

Als éischt, loosst eis d'Sprooch uginn, d'Versioun vun Ubuntu Linux déi mir an der virtueller Maschinn benotze wëllen, an déi néideg Packagen fir de Bau:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

All Packagen déi opgelëscht sinn sinn exklusiv fir PPSSPP gebraucht.

Elo weisen mir d'Versammlungsmatrix un:

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"
      env: PPSSPP_BUILD_TYPE=Linux

E bësse méi iwwer d'Sektioun Matrix. Am Travis CI ginn et zwou Méiglechkeeten fir Bauoptiounen ze kreéieren: déi éischt ass eng Lëscht vu Compileren ze spezifizéieren, Betribssystemtypen, Ëmweltvariablen, etc., no deem eng Matrix vun all méigleche Kombinatioune generéiert gëtt; déi zweet ass eng explizit Indikatioun vun der Matrix. Natierlech kënnt Dir dës zwou Approche kombinéieren an en eenzegaartege Fall addéieren, oder am Géigendeel, et ausgeschloss mat der Sektioun ausgeschloss sinn. Dir kënnt méi iwwer dëst liesen an Travis CI Dokumentatioun.

Alles wat bleift ass fir Projet-spezifesch Montageinstruktiounen ze bidden:

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

Travis CI erlaabt Iech Är eege Kommandoen fir verschidde Stadien vum Liewen vun enger virtueller Maschinn ze addéieren. Sektioun virun_installéieren ausgefouert ier Dir Packagen installéiert. Dann installéieren, déi no der Installatioun vu Packagen aus der Lëscht follegt addons.aptdéi mir uewen uginn. D'Versammlung selwer fënnt am Schrëft. Wann alles gutt gaang ass, da fanne mir eis eran after_erfolg (et ass an dëser Sektioun datt mir statesch Analyse lafen). Dëst sinn net all Schrëtt déi geännert kënne ginn, wann Dir méi braucht, da sollt Dir kucken Travis CI Dokumentatioun.

Fir Liichtegkeet ze liesen, goufen d'Befehle an engem separaten Skript gesat .travis.sh, déi am Projet root gesat gëtt.

Also hu mir déi folgend Datei .travis.yml:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

Ier Dir d'Packagen installéiere wäerte mir d'Submodule aktualiséieren. Dëst ass néideg fir PPSSPP ze bauen. Loosst eis déi éischt Funktioun addéieren .travis.sh (notéiert d'Verlängerung):

travis_before_install() {
  git submodule update --init --recursive
}

Elo komme mir direkt fir den automateschen Start vum PVS-Studio am Travis CI opzestellen. Als éischt musse mir de PVS-Studio Package um System installéieren:

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}

Am Ufank vun der Funktioun travis_install mir installéieren d'Compiler déi mir brauchen mat Ëmfeldvariablen. Dann wann d'Variabel $PVS_ANALYSE Geschäfter Wäert Jo (mir hunn et an der Rubrik uginn schécken während der Baumatrixkonfiguratioun), installéiere mir de Package pvs-studio. Zousätzlech zu dësem ginn och Packagen uginn libio-socket-ssl-perl и libnet-ssleay-perl, si sinn awer erfuerderlech fir d'Resultater ze mailen, sou datt se net néideg sinn wann Dir eng aner Methode gewielt hutt fir Äre Bericht ze liwweren.

Funktioun download_extrakt downloadt an packt de spezifizéierte Archiv aus:

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

Et ass Zäit de Projet zesummenzestellen. Dëst geschitt an der Rubrik Schrëft:

travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}

Tatsächlech ass dëst eng vereinfacht originell Konfiguratioun, ausser fir dës Linnen:

if [ "$PVS_ANALYZE" = "Yes" ]; then
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi

An dëser Rubrik vum Code setzen mir fir cm maachen Fändel fir d'Kompilatiounsbefehl ze exportéieren. Dëst ass néideg fir e statesche Code Analyser. Dir kënnt méi iwwer dëst am Artikel liesen "Wéi lafen PVS-Studio op Linux a MacOS".

Wann d'Versammlung erfollegräich war, da komme mir op after_erfolg, wou mir statesch Analyse maachen:

travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}

Loosst eis déi folgend Zeilen méi no kucken:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                -o PVS-Studio-${CC}.log 
                                --disableLicenseExpirationCheck
plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html

Déi éischt Zeil generéiert eng Lizenzdatei vum Benotzernumm a Schlëssel, dee mir am Ufank uginn hunn wann Dir d'Travis CI Ëmfeldvariablen opstellt.

Déi zweet Linn fänkt d'Analyse direkt un. Fändel -j setzt d'Zuel vun thread fir Analyse, Fändel -l weist Lizenz, Fändel -o definéiert d'Datei fir Logbicher auszeginn, an de Fändel -disableLicenseExpirationCheck néideg fir Test Versiounen, zënter Par défaut pvs-studio-analyzer wäert de Benotzer warnen datt d'Lizenz amgaang ass ofzelafen. Fir dëst ze verhënneren, kënnt Dir dëse Fändel uginn.

D'Protokolldatei enthält rau Output déi net ouni Konversioun gelies ka ginn, also musst Dir d'Fichier als éischt liesbar maachen. Loosst eis d'Logbicher duerchgoen Plog-Converter, an d'Ausgab ass eng HTML Datei.

An dësem Beispill hunn ech beschloss Berichter per Mail mat dem Kommando ze schécken sendmail.

Als Resultat krute mir déi folgend Datei .travis.sh:

#/bin/bash

travis_before_install() {
  git submodule update --init --recursive
}

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}
travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}
travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}
set -e
set -x

$1;

Elo ass et Zäit d'Ännerungen op de Git Repository ze drécken, duerno wäert Travis CI automatesch de Build lafen. Klickt op "ppsspp" fir op d'Build Berichter ze goen:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Mir wäerten en Iwwerbléck iwwer den aktuelle Bau gesinn:

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator
Wann de Bau erfollegräich ofgeschloss ass, kréie mir eng E-Mail mat de Resultater vun der statescher Analyse. Natierlech ass Mailing net deen eenzege Wee fir e Bericht ze kréien. Dir kënnt all Ëmsetzungsmethod wielen. Awer et ass wichteg ze erënneren datt nodeems de Bau ofgeschloss ass, et net méiglech ass op déi virtuell Maschinndateien ze kommen.

Feeler Resumé

Mir hunn de schwieregsten Deel erfollegräich ofgeschloss. Loosst eis elo sécherstellen datt all eis Efforten et wäert sinn. Loosst eis e puer interessant Punkten aus dem statesche Analysebericht kucken, dee mir per Mail komm ass (et war net fir näischt datt ech et uginn hunn).

Geféierlech Optimisatioun

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  memset( &ctx, 0, sizeof( sha1_context ) );
}

PVS-Studio Warnung: V597 De Compiler konnt den 'memset' Funktiounsruff läschen, dee benotzt gëtt fir 'sum' Puffer ze spülen. D'Funktioun RtlSecureZeroMemory() soll benotzt ginn fir déi privat Donnéeën ze läschen. sha1.cpp 325

Dëst Stéck Code ass am séchere Hashing Modul lokaliséiert, awer et enthält e seriéise Sécherheetsfehler (CWE-14). Loosst eis d'Versammlungslëscht kucken, déi generéiert gëtt wann Dir d'Debug Versioun kompiléiert:

; Line 355
  mov r8d, 20
  xor edx, edx
  lea rcx, QWORD PTR sum$[rsp]
  call memset
; Line 356

Alles ass an Uerdnung an d'Funktioun memeset ausgeführt gëtt, doduerch wichteg Donnéeën am RAM iwwerschreiwe, awer freet Iech nach net. Loosst eis d'Versammlungslëscht vun der Release Versioun mat Optimiséierung kucken:

; 354  :
; 355  :  memset( sum, 0, sizeof( sum ) );
; 356  :}

Wéi aus der Oplëschtung gesi ka ginn, huet de Compiler den Uruff ignoréiert memeset. Dëst ass wéinst der Tatsaach, datt an der Funktioun sha1 nom Opruff memeset keng Referenz méi op Struktur ctx. Dofir gesäit de Compiler kee Sënn fir Prozessor Zäit ze verschwenden iwwer d'Erënnerung déi net an Zukunft benotzt gëtt. Dir kënnt dëst fixéieren andeems Dir d'Funktioun benotzt RtlSecureZeroMemory oder ähnlech zu hir.

Richteg:

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  RtlSecureZeroMemory(&ctx, sizeof( sha1_context ) );
} 

Onnéideg Verglach

static u32 sceAudioOutputPannedBlocking
             (u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    if (leftvol >= 0) {
      chans[chan].leftVolume = leftvol;
    }
    if (rightvol >= 0) {
      chans[chan].rightVolume = rightvol;
    }
    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

PVS-Studio Warnung: V547 Ausdrock 'leftvol>= 0' ass ëmmer wouer. sceAudio.cpp 120

Opgepasst op déi aner Branche fir d'éischt if. De Code gëtt nëmmen ausgefouert wann all Konditiounen leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rechtvol < 0 wäert sech falsch erausstellen. Dofir kréie mir déi folgend Aussoen, déi richteg sinn fir déi aner Branche: leftvol <= 0xFFFF, rightvol <= 0xFFFF, leftvol >= 0 и rietsvol >= 0. Notéiert déi lescht zwou Aussoen. Ass et Sënn fir z'iwwerpréiwen wat eng néideg Bedingung ass fir d'Ausféierung vun dësem Stéck Code?

Also kënne mir sécher dës bedingte Aussoen ewechhuelen:

static u32 sceAudioOutputPannedBlocking
(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    chans[chan].leftVolume = leftvol;
    chans[chan].rightVolume = rightvol;

    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

En aneren Szenario. Et ass eng Aart vu Feeler verstoppt hannert dëse redundante Konditiounen. Vläicht hu se net kontrolléiert wat néideg war.

Ctrl+C Ctrl+V Strikes Back

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfData) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

V501 Et gi identesch Ënnerausdréck '!Memory::IsValidAddress(psmfData)' lénks a riets vum '||' Bedreiwer. scePsmf.cpp 703

Opgepasst op de Scheck bannen if. Fannt Dir et net komesch datt mir kucken ob d'Adress valabel ass? psmfDaten, duebel sou vill? Also dat schéngt mir komesch ... Tatsächlech ass dëst natierlech en Tippfeeler, an d'Iddi war déi zwee Inputparameter ze kontrolléieren.

Déi richteg Optioun:

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfStruct) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

Vergiess Variabel

extern void ud_translate_att(
  int size = 0;
  ....
  if (size == 8) {
    ud_asmprintf(u, "b");
  } else if (size == 16) {
    ud_asmprintf(u, "w");
  } else if (size == 64) {
    ud_asmprintf(u, "q");
  }
  ....
}

PVS-Studio Warnung: V547 Ausdrock 'Gréisst == 8' ass ëmmer falsch. syn-att.c 195

Dëse Feeler läit am Dossier ext, Also net wierklech relevant fir de Projet, awer de Käfer gouf fonnt ier ech et gemierkt hunn, also hunn ech decidéiert et ze verloossen. No allem ass dësen Artikel net iwwer d'Iwwerpréiwung vu Feeler, mee iwwer d'Integratioun mam Travis CI, a keng Konfiguratioun vum Analyser gouf duerchgefouert.

Variabel Gréisst gëtt vun enger konstanter initialiséiert, awer et gëtt guer net am Code benotzt, bis zum Bedreiwer if, déi natierlech gëtt falsch beim Iwwerpréiwen vun de Bedéngungen, well, wéi mir eis erënneren, Gréisst gläich op null. Spéider Kontrollen maachen och kee Sënn.

Anscheinend huet den Auteur vum Codefragment vergiess d'Variabel ze iwwerschreiwen Gréisst virun deem.

Stop

Hei wäerte mer wahrscheinlech mat de Feeler ophalen. Den Zweck vun dësem Artikel ass d'Aarbecht vum PVS-Studio zesumme mam Travis CI ze demonstréieren, an net de Projet esou grëndlech wéi méiglech ze analyséieren. Wann Dir méi grouss a méi schéin Feeler wëllt, kënnt Dir se ëmmer bewonneren hei :).

Konklusioun

Mat Webservicer fir Projeten ze bauen zesumme mat der Praxis vun der inkrementeller Analyse erlaabt Iech vill Probleemer direkt nom Fusiounscode ze fannen. Wéi och ëmmer, ee Bau ass vläicht net genuch, sou datt d'Tester zesumme mat der statescher Analyse d'Qualitéit vum Code wesentlech verbesseren.

Nëtzlech Adressen

Wéi konfiguréiert PVS-Studio am Travis CI mam Beispill vun engem PSP Spillkonsolemulator

Wann Dir dësen Artikel mat engem engleschsproochege Publikum wëllt deelen, benotzt w.e.g. den Iwwersetzungslink: Maxim Zvyagintsev. Wéi Ariichten PVS-Studio am Travis CI mam Beispill vun PSP Spill Konsol Emulator.

Source: will.com

Setzt e Commentaire