MISRA C:kamp for kodekvalitet og sikkerhed

MISRA C:kamp for kodekvalitet og sikkerhed

For et par år siden fik PVS-Studio-analysatoren sine første diagnostiske regler for at kontrollere programkodens overensstemmelse med MISRA C- og MISRA C++-standarderne. Vi indsamlede feedback og så, at vores kunder var interesserede i at bruge analysatoren til at kontrollere deres projekter for MISRA-overholdelse. Så vi besluttede at videreudvikle analysatoren i denne retning. Artiklen dækker MISRA C/C++-standarden og MISRA Compliance-rapporten. Det viser også, hvad vi allerede nåede at gøre, og hvad vi planlægger at opnå ved årets udgang.

Sådan startede det

Vores virksomhed begyndte at arbejde på en statisk kodeanalysator tilbage i 2006. På det tidspunkt undergik it-verdenen en glidende overgang:applikationer begyndte at migrere fra 32-bit-systemer til 64-bit. Mange udviklere begyndte at støde på uventede problemer. Vores produkt, hvis navn dengang var Viva64, hjalp udviklere med at lede efter kodefejl, der opstod, efter at de havde tilpasset applikationer til 64-bit systemer. Over tid lærte analysatoren at undersøge projekter for fejlmønstre relateret til stavefejl, uinitialiserede variabler, uopnåelig kode, udefineret adfærd osv. I øjeblikket giver analysatoren over 1000 diagnostik.

Før 2018 placerede vi PVS-Studio som et værktøj, der opdager kodefejl. I 2018 indså vi, at en betydelig del af de fejl, som vi lærte at opdage, samtidig var potentielle sårbarheder. Fra 2018 har PVS-Studio været et værktøj til Static Application Security Testing (SAST). Samtidig begyndte vi at klassificere både ny og eksisterende diagnostik i overensstemmelse med Common Weakness (CWE), SEI CERT Coding (CERT), MISRA C/C++. I 2021 sluttede AUTOSAR sig til denne liste.

I 2018 begyndte vi at understøtte indlejrede systemer, og det fik os til at støtte MISRA og AUTOSAR. Analysatoren understøttede følgende systemer:

  • Windows. IAR Embedded Workbench, C/C++ Compiler til ARM C, C++;
  • Windows/Linux. Keil µVision, DS-MDK, ARM Compiler 5/6 C, C++;
  • Windows/Linux. Texas Instruments Code Composer Studio, ARM Code Generation Tools C, C++;
  • Windows/Linux/macOS. GNU Arm Embedded Toolchain, Arm Embedded GCC compiler, C, C++.

Du kan finde detaljerede instruktioner om, hvordan du bruger PVS-Studio til indlejret udvikling på vores hjemmeside.

I modsætning til desktop-projekter er mange indlejrede projekter udviklet i henhold til MISRA-anbefalinger. Så vi tænkte, at det ville være en god idé at programmere vores analysator til at understøtte standarden. Siden da har vi langsomt udviklet regler for denne standard og indsamlet feedback.

Vi ventede på, at efterspørgslen skulle dukke op, og det lod os ikke vente længe. Folk skrev beskeder til os, spurgte om analysatorens funktioner, forsøgte at analysere deres projekter. For os betød det, at det var tid til at udvikle vores analysator i MISRA-retningen yderligere. De fleste af vores kunder var interesserede i MISRA C i stedet for i MISRA C++, og derfor besluttede vi i første omgang at øge MISRA C-dækningen. Brugere var også interesserede i MISRA Compliance-rapporten, som vi også støttede for nylig.

Og lad os nu tale om selve MISRA C/C++-standarden.

Om MISRA C/C++ standard

MISRA-standarden er designet til kritiske indlejrede systemer, hvor kravene til kvalitet, pålidelighed og portabilitet skal opfyldes. Sådanne systemer bruges i bilindustrien, flykonstruktion, medicin, rumindustrien og andre industriområder. Prisen for en programmatisk fejl i sådanne systemer kan være menneskers sundhed og liv eller store økonomiske tab eller tab af omdømme.

MISRA C-standarden gælder for programmer i C. Standarden opdateres løbende og indeholder i øjeblikket 143 regler og 16 direktiver. Reglerne er opdelt i kategorier:

  • Obligatorisk (10 regler) – de strenge regler. Manglende overholdelse af dem forårsager næsten altid en fejl;
  • Påkrævet (101 regler) – mindre strenge regler. De forbedrer kodelæsbarheden, forbyder usikre sprogkonstruktioner og forbyder funktioner – som malloc – hvis forkert brug fører til fejl.
  • Rådgivende (32 regler) – ikke-obligatoriske anbefalinger.

Lad os se på et par påkrævede regler, da denne kategori er den største.

Regel MISRA-C-11.8 . Medvirkende bør ikke fjerne const/volatile kvalifikation fra den type, der peges på af en pointer. Diagnostisk for denne regel - V2567. Her er eksemplet på den afvigelse, som analysatoren fandt i reliance-edge-projektet:

V2567 [MISRA-C-11.8] Castet bør ikke fjerne 'const'-kvalifikationen fra den type, der peges på af en pointer. toolcmn.c 66

uint8_t RedFindVolumeNumber(const char *pszVolume)
{
  const char     *pszEndPtr;
  ....
  ulNumber = strtoul(pszVolume, (char **)&pszEndPtr, 10);
  ....
}

Reglen advarer om, at dette mønster fører til udefineret adfærd.

Regel MISRA-C-7.1. Oktale konstanter bør ikke anvendes. Diagnostisk for denne regel - V2501. Analysatoren fandt også sådanne konstanter i det samme reliance-edge-projekt:

V2501 [MISRA-C-7.1] Oktal konstant '0666' bør ikke bruges. fsstress.c 1376

static void creat_f(int opno, long r)
{
  int e;
  pathname_t f;
  int fd;
  ....
  fd = creat_path(&f, 0666);  //<=
  e = fd < 0 ? errno : 0;
  ....
}

Reglen siger, at brugen af ​​oktale bogstaver kan hindre kodelæsbarhed, især når en udvikler skimmer igennem den. Fejlfortolkning af numeriske værdier kan resultere i forskellige fejl.

Regel MISRA-C-11.1. Konverteringer bør ikke udføres mellem pointer til funktion og nogen anden type. Diagnostisk for denne regel - V2590.

V2590 Konverteringer bør ikke udføres mellem pointer til funktion og nogen anden type. Overvej at inspicere udtrykket '(fp) &foo'.

void foo(int32_t x);
typedef void (*fp)(int16_t x);

void bar(void)
{
  fp fp1 = (fp)&foo;
}

Markøren til fp1 funktion tager værdien af ​​markøren til foo funktion, som ikke matcher argumenterne og returværdien. Sprogstandarden tillader sådanne konverteringer. MISRA C-standarden advarer dog om, at de forårsager udefineret adfærd.

Hvis du bare begynder at bruge MISRA-standarden og anvender alle reglerne på din kode på én gang, vil det se nogenlunde sådan ud:

Næsten hver sprogkonstruktion har sin egen regel eller endda flere regler. Derfor er kodeskrivning i overensstemmelse med MISRA-standarden ingen spøg. Heldigvis har vi statiske kodeanalysatorer til at hjælpe os. Sådanne analysatorer leveres med et sæt diagnostik, som registrerer regelovertrædelser af standarden.

MISRA skabte sine regler under hensyntagen til risikable træk ved sproget og dets finesser. Overholdelse af omhyggelige regler hjælper udviklere med at skrive sikker kode. De opdager lettere fejl. De behøver ikke at holde alle de subtile sprogfunktioner i hovedet og bekymre sig om programmets adfærd, når det er porteret til et andet softwaremiljø eller hardware. MISRA-udviklere har grundigt studeret hele C-sprogstandarden i søgen efter måder at skyde sig selv i foden på. Nu kan vi trække på deres erfaring i stedet for at lære sprogstandarden fra ende til anden.

At overholde kodningsstandarden kan være en stor udfordring for en udvikler. Det pålægger mange begrænsninger for kodeskrivningen. Men denne tilgang reducerer markant antallet af fejl, der kan opstå, når du kører et program, for eksempel i en flymotor. Høj applikationssikkerhed betaler for den tid og de penge, du bruger for at sikre, at din kode overholder standarden. Find mere information om standarden, og hvordan du bruger den i dine projekter i artiklen:Hvad er MISRA, og hvordan man laver det .

Og lad os nu gå videre til udviklingen af ​​vores statiske analysator i MISRA-retningen.

Vores planer og nuværende fremskridt

Nu ved vi, at udviklere vil bruge vores analysator til at kontrollere deres kode for overensstemmelse med MISRA-standarden. Derfor udvikler vi aktivt analysatoren i denne retning.

Vi så efterspørgslen efter kodeanalyse, der overholder MISRA C-standarden. Vores team fortsatte med at udvikle analysatoren til konkurrencedygtige niveauer og sætte mål for os selv:

  • øg MISRA-dækningen med op til 80 % ved udgangen af ​​dette år;
  • giv en mulighed for at generere en MISRA-overensstemmelsesrapport.

Fra april prioriterede vi at skrive MISRA C-diagnostikken. Vores team udvidede sig, og det forbedrede udviklingsprocessen. I øjeblikket dækker PVS-Studio 60% af MISRA C-standarden. Inden november planlægger vi at øge dækningen op til 75 % og i januar 2022 – 80 % eller mere.

Mens jeg skrev denne artikel, fik betaversionen af ​​PVS-Studio analysator funktionen til at generere MISRA Compliance-rapport. PlogConverter.exe-værktøjet til Windows og plog-konverter til Linux kan nu konvertere en "rå" analysatorrapport til MISRA Compliance-rapport. Lad os nu tale om MISRA Compliance-rapport.

Her er et par eksempler fra den nylige MISRA C-diagnostik.

V2594. MISRA. Styrende udtryk bør ikke være invariante.

Styring af udtryk i if , ?: , mens , for , gør , skift bør ikke være invariant, dvs. kontrollerende udtryk bør ikke altid føre til udførelse af den samme kodegren. En invariant værdi i et kontrollerende udtryk kan indikere en programfejl.

void adjust(unsigned error)
{
  if (error < 0)
  {
    increase_value(-error);
  }
  else
  {
    decrease_value(error);
  }
}

Dette eksempel illustrerer fejlen:betingelsen er altid falsk, fordi funktionen modtager et heltal uden fortegn. Som følge heraf er decrease_value funktion kaldes altid. Compileren kan fjerne kodegrenen med increase_value funktion.

V2598. MISRA. Arraytyper med variabel længde er ikke tilladt.

Erklæring af arrays med variabel længde kan føre til et stackoverløb og potentielle sårbarheder i programmet.

void foo(size_t n)
{
  int arr[n];
  // ....
}

Overførsel af stort antal n kan føre til et stackoverløb, da arrayet bliver for stort og optager mere hukommelse, end der er tilgængeligt.

MISRA C-standarden indeholder 143 regler og 16 direktiver. Det ville være rart at have en generel rapport, der kunne vise kodens overensstemmelse med standarden i en bekvem form og indeholde oplysninger om alle regelafvigelser. En sådan rapport findes. Dens navn er MISRA Compliance.

generering af MISRA-overholdelsesrapport

Ifølge MISRA C-standarden kan det være uberettiget for udviklere at overholde alle MISRA-regler. Derfor kræver det at udstede en MISRA Compliance-rapport om koden, der overholder alle obligatoriske regler. Standarden tillader også afvigelser fra de påkrævede regler. En udvikler skal bekræfte afvigelser fra regler og dokumentere dem.

Som tidligere nævnt kan betaversionen af ​​vores analysator nu generere sådanne rapporter. I øjeblikket har en rapport en form for HTML-side genereret af PlogConverter.exe-værktøjet til Windows og Plog-konverter til Linux.

Rapporten indeholder en tabel over overholdelse af reglerne for hver af MISRA C-reglerne og en generel konklusion.

Retningslinjen kolonnen indeholder regler og direktivnummer fra MISRA C-standarden.

Kategorien - viser kategorien af ​​en regel eller et direktiv angivet i standarden.

MISRA C-standarden giver dig mulighed for at hæve overholdelsesniveauet. Derfor er Omkategorisering afspejler den nye regel eller direktivkategori indstillet af brugeren i overensstemmelse med GRP (Guideline Re-categorization Plan). Kun tre overgange er mulige:

  • Påkrævet -> Obligatorisk;
  • Rådgivning -> Påkrævet;
  • Rådgivende -> Obligatorisk.

I vores tilfælde er GRP en txt-fil. Et fileksempel på acceptable skift:

Rule 15.3 = Mandatory
Rule 16.4 = Mandatory
Rule 17.5 = Required

Hvis denne fil indeholder en kategori ned-shift, vil plog-konverteren udsende en fejlmeddelelse og vil ikke generere rapporten.

Overholdelse kolonne indeholder oplysninger om den kontrollerede kodes overensstemmelse med en regel eller et direktiv:

  • Overholder – projektet har ingen afvigelser fra reglen;
  • Afvigelser – afvigelser fra reglen blev opdaget, men udvikleren begrundede årsagen til, at han bevidst overtræder denne regel. Hvis du ønsker, at analysatoren skal ignorere en specifik advarsel, skal du markere den som falsk alarm (Marker som falsk alarm). Antallet af godkendte afvigelser vises i parentes ved siden af ​​status for afvigelser;
  • Overtrædelser – der er mindst én afvigelse fra reglen, som ikke er dokumenteret (ikke begrundet og ikke markeret som FA). Antallet af sådanne afvigelser er angivet i parentes;
  • Ikke understøttet – analysatoren understøtter ikke denne regel endnu.

Under tabellen vil du se rapporten, der viser, om dit projekt overholder eller ikke overholder MISRA C-standarden. Kompatibel kode opfylder følgende betingelser:

  • Alle obligatoriske regler har statussen Overensstemmende eller Ikke understøttet;
  • Alle påkrævede regler har statussen Overensstemmende og/eller Afvigelser eller Ikke understøttet;
  • Rådgivningsregler har en status;

Hvis koden ikke overholder standarden, vil hjælpeprogrammet fremhæve de overtrådte statusser for reglerne med rødt.

Indtil begyndelsen af ​​oktober 2021 vil genereringen af ​​MISRA Compliance-rapporten være tilgængelig i betaversion (for at få betaen skal du venligst udfylde feedbackformularen). Så planlægger vi at frigive en ny version af PVS-Studio analysator. PVS-Studio 7.15 vil være i stand til at generere denne rapport.

For at generere MISRA Compliance-rapporten på Windows skal du først køre analysen af ​​projektet. Kør derefter Plog-converter.exe-værktøjet med følgende argumenter:

"C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" "path_to_report_file" \
-t misra -o "path_to_MISRA_report" --grp "path_to_grp.txt"

For at generere rapporten om Linux skal du også køre analysen. Ring derefter til Plog-konverteren.

plog-converter "path_to_report_file" -t misra -o "path_to_MISRA_report" \
--grp "path_to_grp.txt"

MISRA Compliance-rapporten viser, at dit projekts kode overholder MISRA-standarden. Vi bestræber os på at reducere antallet af ikke understøttede statusser i din rapport. Udviklingen af ​​ny MISRA-diagnostik resulterer ikke kun i diagnosekoden og dokumentationsteksten. Det giver også et værdifuldt resultat for udviklere. Og det er hvad det følgende afsnit handler om.

MISRA-diagnostik:hvorfor det kan være spændende og nyttigt at skrive dem

Hvilket output giver MISRA-diagnostikudviklingen?

For det første er det forståelse af sikker kodningsprincipper. Mens vi udvikler diagnostik for generel analyse, forsøger vi at minimere antallet af udstedte advarsler. Endnu en MISRA-diagnostik kan udsende tusindvis af beskeder på et mellemstort projekt. Efter at vi har kørt en ny diagnostik på vores testprojektdatabase, kan en rapport se sådan ud:

For det andet - viden om specifikke og uventede træk ved et sprog. For eksempel, er der nogen der kan huske den udpegede initialisering? Er der nogen, der ved, hvordan man bruger static søgeord korrekt i en array-formel parameterdeklarator?

int array[] = { 1, 2, 4, [8]={256} };

void foo(int [static 20]);

For det tredje lærer du en million måder at få uspecificeret, udefineret eller implementeringsafhængig adfærd. Du begynder at genkende potentielt usikre kodefragmenter.

Og ny udvikling af MISRA-diagnostik kan også give anledning til General Analysis-diagnostik.

Lad os tale om den sidste mere detaljeret. Normalt dukker ideerne til ny generel analysediagnostik op i følgende tilfælde:

  • når vi studerer et sprog (inklusive nye standarder) og kompilatorer. Vi genkender de tilfælde, hvor implementering af en bestemt sprogkonstruktion kan føre til en fejl;
  • når vi leder efter fejl i vores kode. Et populært mønster kan være en fejl, hvorfor så ikke implementere en søgning efter sådanne fejl;
  • når vi yder teknisk support til kunder. Bekymrede udviklere kommer ofte frem med ideer;
  • når vi læser artikler, hvor forfatteren står over for et spændende fejlmønster;
  • når vi studerer sikker kodningsstandarder.

Så for nylig dukkede en ny generel analysediagnostik op på grund af implementeringen af ​​en af ​​MISRA C-reglerne. Reglen siger:'Oktale og hexadecimale escape-sekvenser bør afsluttes'. Hvorfor? Se på denne linje:

const char *str = "\x0exit";

Denne streng er 4 tegn lang i stedet for 5, som det umiddelbart kan se ud. \x0e sekvens er et tegn, der har 0xE-koden - ikke et tegn, der har en nulkode, efterfulgt af bogstavet e .

Derfor skal man ifølge standarden afslutte escape-sekvensen på en af ​​to måder:

  • afslutning af strengen literal;
  • start af en ny escape-sekvens.

For eksempel:

const char *str1 = "\x0" "exit"; 
const char *str2 = "\x1f\x2f";

Vi fandt denne regel nyttig for projekter, der ikke er skrevet i henhold til MISRA-standarden. Sådan optrådte to vores diagnoser på én gang:V1074 og V2602. Det er klart, at de har den samme kode under motorhjelmen.

Her er endnu et tilfælde, hvor ny diagnostik dukkede op på grund af samarbejdet med MISRA. Det hele startede, da vi føjede covid-sim-projektet til basen af ​​testprojekter til test af PVS-Studio-analysatoren. Projektet viste sig at være lille og tværplatform, så det var velegnet til MISRA diagnostiske test. Før vi supplerer basen, finder vi det nyttigt at se advarslerne igennem for at finde ud af mønstre af falske positiver. Dette kunne være en almindelig kontrol. Analysatoren fangede dog V2507-advarslen, der så ud til at være en falsk positiv:

if (radiusSquared > StateT[tn].maxRad2) StateT[tn].maxRad2 = radiusSquared;
{
  SusceptibleToLatent(a->pcell);
  if (a->listpos < Cells[a->pcell].S)
  {
    UpdateCell(Cells[a->pcell].susceptible, a->listpos, Cells[a->pcell].S);
    a->listpos = Cells[a->pcell].S;
    Cells[a->pcell].latent[0] = ai;
  }
}
StateT[tn].cumI_keyworker[a->keyworker]++;

V2507-diagnostiken finder betingede udsagn, hvis kroppe ikke er indesluttet i krøllede seler.

Som du kan se, har kodefragmentet seler. Fejlede analysatoren? Lad os se nærmere. Det bliver tydeligt, at kroppen af ​​hvis erklæringen er på linje med den betingede erklæring. Og bøjlerne har intet at gøre med hvis på nogen måde.

For det første beviser dette eksempel, at MISRA-standardtilgangen virker. Det reducerer antallet af fejl i koden for kritiske indlejrede systemer. Når alt kommer til alt, hvis kroppen af ​​hvis udsagnet var i parentes, så ville den logiske fejl være let at bemærke.

For det andet er vi kommet med en idé om en ny generel analysediagnostik. Diagnosen udsender en advarsel, hvis følgende betingelser er opfyldt for hvis erklæring:

  • hele hvis sætning er skrevet på én linje og har kun et da filial;
  • den næste erklæring efter hvis er en sammensat sætning, og den starter ikke på samme linje med hvis .

Læs mere om den diagnostiske udvikling af V1073 her.

Konklusion

Kodepålidelighed og -sikkerhed kræver overholdelse af strenge og omhyggelige regler for en bestemt kodeskrivning. Undgå farlige sprogkonstruktioner og -funktioner:deres misbrug fører til fejl. Brug statiske analysatorer, for eksempel PVS-Studio, til at kontrollere koden for overholdelse. Resultatet af kontrollen vil være MISRA Compliance-rapporten.

Flere oplysninger om, hvordan du forbedrer kodesikkerheden ved hjælp af statisk analyse, i følgende artikler:

  • PVS-Studio finder sikkerhedsfejl og giver applikationssikkerhed. Rapport fra Forrester Research om SAST, 3. kvartal 2020. Rapport fra Forrester Research om SAST, 3. kvartal 2020.
  • OWASP, sårbarheder og taint-analyse i PVS-Studio til C#. Rør rundt, men ryst ikke.
  • Teknologier, der bruges i PVS-Studio-kodeanalysatoren til at finde fejl og potentielle sårbarheder.