Hvorfor jeg ikke kan lide syntetiske tests

Hvorfor jeg ikke kan lide syntetiske tests

Jeg kan ikke lide det, når folk bruger kunstige kodeeksempler til at evaluere de diagnostiske muligheder for statiske kodeanalysatorer. Der er et bestemt eksempel, jeg vil diskutere for at forklare min negative holdning til syntetiske tests.

Bill Torpey skrev for nylig et blogindlæg med titlen "Even Mo' Static", hvor han delte sit syn på resultaterne af test af Cppcheck og PVS-Studio analysatorer på itc-benchmarks-projektet, som er et sæt statiske analysebenchmarks fra Toyota ITC.

Det indlæg forstyrrede mig, fordi det ville efterlade dig med et indtryk af, at Cppchecks og PVS-Studios muligheder var meget ens. Det, der følger af artiklen, er, at den ene analysator er bedre til at diagnosticere nogle typer fejl og den anden til at diagnosticere andre typer fejl, men deres muligheder er generelt de samme.

Jeg synes, det er en forkert konklusion. Min mening er, at vores analysator, PVS-Studio, er flere gange kraftigere end Cppcheck. Nå, det er ikke engang en "mening" - det er det, jeg ved med sikkerhed!

Men da det ikke er indlysende for en udefrakommende iagttager, at PVS-Studio er ti gange bedre end Cppcheck, må der være en grund til det. Jeg besluttede at tage et kig på det projekt, itc-benchmarks, og finde ud af, hvorfor PVS-Studio ikke ydede sit bedste på den kodebase.

Jo mere jeg gravede, jo større irritation følte jeg. Der var et bestemt eksempel, der gjorde mig virkelig sindssyg, og jeg vil fortælle dig om det om et øjeblik. Hvad jeg har at sige som konklusion er dette:Jeg har ingen klager mod Bill Torpey. Han skrev en god, ærlig artikel. Tak, Bill! Men jeg har klager over Toyota ITC. Jeg synes personligt, at deres kodebase er lort. Ja, det er en ligefrem udtalelse, men jeg tror, ​​jeg har nok kompetence og erfaring til at debattere om statiske kodeanalysatorer og måder at evaluere dem på. Efter min mening kan itc-benchmarks ikke bruges til tilstrækkeligt at evaluere værktøjernes diagnostiske muligheder.

Nu, her er testen, der dræbte mig.

Det er en test for nul pointer dereference:

void null_pointer_001 ()
{
  int *p = NULL;
  *p = 1; /*Tool should detect this line as error*/
          /*ERROR:NULL pointer dereference*/
}

Cppcheck analysator rapporterer en fejl i denne kode:

Null pointer dereference: p

PVS-Studio-analysatoren holder stille, selvom den har diagnostisk V522 til sådanne tilfælde.

Så betyder det, at PVS-Studio er dårligere til at diagnosticere dette eksempel end Cppcheck? Nej, det er lige modsat:det er bedre!

PVS-Studio forstår, at denne kode er skrevet med vilje, og der er ingen fejl der.

I visse tilfælde skriver programmører sådan kode med vilje at få programmet til at kaste en undtagelse, når der opstår en nul pointer dereference. Dette trick bruges i test og specifikke kodefragmenter, og jeg har set det mere end én gang. Her er for eksempel, hvordan det kan være i et virkeligt projekt:

void GpuChildThread::OnCrash() {
  LOG(INFO) << "GPU: Simulating GPU crash";
  // Good bye, cruel world.
  volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
  *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
}

Derfor har vi inkluderet en række undtagelser i PVS-Studios V522 diagnostiske regel, så den ikke bliver gal med kode på den måde. Analysatoren forstår, at null_pointer_001 er en kunstig funktion; der er bare ingen fejl, der beskæftiger sig med at tildele nul til en pointer og derefter straks dereferencere den i rigtige funktioner. Selve funktionsnavnet er også et tegn for analysatoren på, at "nul-markøren" her ikke er et uheld.

I sådanne tilfælde har V522-diagnostik en undtagelse A6. Det er denne undtagelse, den syntetiske funktion null_pointer_001 falder ind under. Dette er beskrivelsen af ​​A6-undtagelsen:

Variablen dereferences i brødteksten af ​​en funktion, hvis navn indeholder et af følgende ord:

  • fejl
  • standard
  • nedbrud
  • null
  • test
  • overtrædelse
  • kast
  • undtagelse

Før den dereferences, er variablen tildelt 0 en linje tidligere.

Den pågældende syntetiske test passer fuldstændig ind i denne beskrivelse. For det første indeholder funktionsnavnet ordet "nul". For det andet tildeles variablen nul præcis én linje tidligere. Undtagelsen afslørede uvirkelig kode, hvilket det i virkeligheden er, fordi det er en syntetisk test.

Det er for disse subtile detaljer, jeg ikke kan lide syntetiske tests!

Det er ikke den eneste klage, jeg har mod itc-benchmarks. For eksempel er der en anden test i samme fil:

void null_pointer_006 ()
{
  int *p;
  p = (int *)(intptr_t)rand();
  *p = 1; /*Tool should detect this line as error*/
          /*ERROR:NULL pointer dereference*/
}

randen funktion kan returnere 0, som så bliver til NULL. PVS-Studio analysator ved endnu ikke hvad rand kan vende tilbage, så den har ingen mistanke om denne kode.

Jeg bad mine kolleger om at lære analysatoren bedre at forstå, hvordan præcis rand fungerer arbejder. Der er intet valg; vi er nødt til at glatte værktøjet manuelt, så det kunne klare sig bedre på den pågældende testbase. Vi er tvunget til at gøre det, da folk bruger den slags testdragter til at evaluere analysatorer.

Men du skal ikke bekymre dig. Jeg lover, at vi stadig vil arbejde på den virkelige, brugbare diagnostik som før i stedet for at tilpasse analysatoren til test. Vi kan måske polere PVS-Studio lidt for itc-benchmarks, men ikke som en topprioritet opgave og kun for de sager, der giver i det mindste nogen mening.

Jeg vil have udviklere til at forstå, at eksemplet med rand viser faktisk ikke noget. Det er syntetisk, totalt langt ude. Ingen skriver programmer på den måde; der er ingen rigtige fejl som den.

Forresten, hvis rand funktion returnerer 1400 i stedet for 0, det bliver ikke bedre. Sådan en pointer kan under alle omstændigheder ikke afvises. Så denne null pointer dereference er et eller andet mærkeligt privat tilfælde af fuldstændig forkert kode, som simpelthen blev lavet af suiteforfatterne, og som du aldrig kommer til at se i virkeligheden.

Jeg ved, hvad de egentlige programmeringsproblemer er. Disse er blandt andet slåfejl, og vores værktøj fanger jævnligt hundredvis af dem ved hjælp af f.eks. diagnostisk V501. Det er sjovt, men jeg har ikke fundet en test i itc-benchmarks, der tjekker, om værktøjer kan få øje på "if (a.x ==a.x)"-tastfejlmønsteret. Ikke en eneste test!

Det viser sig, at itc-benchmarks ignorerer analysatorernes tastefejlsøgningsmuligheder, mens vores læsere helt sikkert ved, hvor udbredte defekter af denne type er. Og hvad det projekt har, er testcases, som jeg finder dumme, og som aldrig findes i rigtige programmer. Jeg kan ikke forestille mig at snuble over kode som den nedenfor, hvilket resulterer i en array-overskridelse i et rigtigt, seriøst projekt:

void overrun_st_014 ()
{
  int buf[5];
  int index;
  index = rand();
  buf[index] = 1; /*Tool should detect this line as error*/
                  /*ERROR: buffer overrun */
  sink = buf[idx];
}

Den eneste type programmer, du sikkert kunne finde, er elevernes programmeringsøvelser.

Samtidig ved jeg, at du med stor sandsynlighed støder på følgende tastefejl i et seriøst projekt:

return (!strcmp (a->v.val_vms_delta.lbl1,
                 b->v.val_vms_delta.lbl1)
        && !strcmp (a->v.val_vms_delta.lbl1,
                    b->v.val_vms_delta.lbl1));

Denne fejl blev fundet af PVS-Studio i GCC-kompilerens kode:de samme strenge sammenlignes to gange.

Så pakken inkluderer tests til diagnosticering af eksotisk kode med rand men nul test for klassiske tastefejl.

Jeg kunne blive ved og ved, men jeg vil hellere stoppe. Jeg har sluppet dampen og har det bedre nu. Tak fordi du læste. Nu har jeg en artikel til støtte for min mening om syntetiske fejlbaser.

Velkommen til at installere og prøve den mest kraftfulde kodeanalysator PVS-Studio.

Referencer:

  • PVS-Studios diagnostiske muligheder.
  • Database over virkelige fejl fundet af PVS-Studio i open source-projekter.
  • Myter om statisk analyse. Den femte myte - et lille testprogram er nok til at evaluere et værktøj.
  • OPDATERING. Hvad er der med PVS-Studios dækning af Toyota ITC Benchmark?