Ohjelmointi

4 yleistä C-ohjelmointivirhettä - ja 5 vinkkiä niiden välttämiseksi

Muutama ohjelmointikieli voi täyttää C: n pelkän nopeuden ja konetason tehon suhteen. Tämä toteamus oli totta 50 vuotta sitten, ja se on totta myös nykyään. On kuitenkin syytä, että ohjelmoijat keksivät termin "jalka-ase" kuvaamaan C: n sellaista voimaa. Jos et ole varovainen, C voi puhaltaa varpaasi - tai jonkun muun.

Tässä on neljä yleisintä virhettä, joita voit tehdä C: llä, ja viisi vaihetta, jotka voit tehdä estääkseen ne.

Yleinen C-virhe: Ei vapauta malloc-muistia (tai vapauttamista useammin kuin kerran)

Tämä on yksi suurimmista virheistä C: ssä, joista monet liittyvät muistin hallintaan. Kohdennettu muisti (tehty käyttämällä malloc Ohjelmoijan tehtävä on hävittää kyseinen muisti, kun sitä ei enää käytetä. Toistuvien muistipyyntöjen vapauttaminen epäonnistuu ja päädyt muistivuotoon. Yritä käyttää muistialueella, joka on jo vapautettu, ja ohjelma kaatuu - tai mikä vielä pahempaa, onttuu ja tulee alttiiksi hyökkäykselle käyttämällä tätä mekanismia.

Huomaa, että muisti vuotaa pitäisi kuvata vain tilanteita, joissa muisti on oletettu vapautua, mutta ei ole. Jos ohjelma jatkaa muistin jakamista, koska muistia todella tarvitaan ja käytetään työhön, sen muistin käyttö voi ollatehoton, mutta tarkkaan ottaen se ei ole vuotoja.

Yleinen C-virhe: Taulukon lukeminen rajojen ulkopuolella

Tässä meillä on vielä yksi C: n yleisimmistä ja vaarallisimmista virheistä. Matriisin loppu lukea voi palauttaa roskatiedot. Kirjoittaminen taulukon rajojen yli voi vahingoittaa ohjelman tilaa tai kaataa sen kokonaan tai, mikä pahinta, siitä voi tulla haittaohjelmien hyökkäysvektori.

Joten miksi taulukon rajojen tarkastamisen taakka jätetään ohjelmoijalle? Virallisessa C-spesifikaatiossa taulukon lukeminen tai kirjoittaminen sen rajojen ulkopuolelle on "määrittelemätöntä käyttäytymistä", mikä tarkoittaa, että spesifikaatilla ei ole sananvaltaa tapahtuvan. Kääntäjän ei tarvitse edes valittaa siitä.

C on pitkään kannattanut ohjelmoijan antamista voimalle jopa omalla vastuullaan. Kääntäjä ei tavallisesti loukkaa rajojen ulkopuolista lukemista tai kirjoittamista, ellet ota erikseen käyttöön kääntäjävaihtoehtoja suojautua sitä vastaan. Lisäksi voi olla mahdollista ylittää matriisin raja ajon aikana tavalla, jota edes kääntäjän tarkistus ei voi suojata.

Yleinen C-virhe: Ei tarkistamalla malloc

malloc ja calloc (ennalta nollatulle muistille) ovat C-kirjastotoimintoja, jotka hankkivat kasaan varatun muistin järjestelmästä. Jos he eivät pysty varaamaan muistia, ne muodostavat virheen. Aikoina, jolloin tietokoneilla oli suhteellisen vähän muistia, oli mahdollisuus soittaa malloc ei ehkä onnistu.

Vaikka tietokoneilla on nykyään gigatavua RAM-muistia, heillä on aina mahdollisuus malloc voi epäonnistua, varsinkin suuressa muistipaineessa tai suurten muistilaattojen jakamisessa kerralla. Tämä pätee erityisesti C-ohjelmiin, jotka "jakavat levylle" suuren muistilohkon käyttöjärjestelmästä ja jakavat sen sitten omaan käyttöönsä. Jos ensimmäinen allokointi epäonnistuu, koska se on liian suuri, saatat pystyä ansaan kieltäytymisen, pienentämään allokointia ja virittämään ohjelman muistin käytön heuristiikkaa. Mutta jos muistin allokointi epäonnistuu, koko ohjelma voi mennä vatsaan ylöspäin.

Yleinen C-virhe: Käyttäminen mitätön * yleisiä viitteitä muistiin

Käyttämällämitätön * muistiin osoittaminen on vanha tapa - ja huono tapa. Muistiviitteiden tulisi aina olla hiiltyä*, allekirjoittamaton merkki *taiuintptr_t *. Nykyaikaisten C-kääntäjien pitäisi tarjota uintptr_t osana stdint.h

Kun jokin näistä tavoista on merkitty, on selvää, että osoitin viittaa muistin sijaintiin tiivistelmässä jonkin määrittelemättömän objektityypin sijaan. Tämä on kaksinkertaisen tärkeää, jos suoritat osoitinmatematiikkaa. Kanssauintptr_t * ja vastaavat, kokoelementti, johon osoitetaan, ja miten sitä käytetään, ovat yksiselitteisiä. Kanssa mitätön *, ei niin paljon.

Yleisten C-virheiden välttäminen - 5 vinkkiä

Kuinka vältät nämä liian yleiset virheet työskennellessäsi muistin, taulukoiden ja osoittimien kanssa C: ssä? Pidä nämä viisi vinkkiä mielessä.

Rakenna C-ohjelmat siten, että muistin omistajuus pidetään selvänä

Jos olet vasta aloittamassa C-sovellusta, kannattaa miettiä, miten muisti jaetaan ja vapautetaan yhtenä ohjelman organisaation periaatteista. Jos on epäselvää, missä tietyn muistin varaus on vapautettu tai missä olosuhteissa, pyydät ongelmia. Tee ylimääräinen vaivaa, jotta muistin omistajuus olisi mahdollisimman selkeä. Teet itsellesi (ja tuleville kehittäjille) palveluksen.

Tämä on Rustin kaltaisten kielten takana oleva filosofia. Ruoste tekee mahdottomaksi kirjoittaa oikein kääntyvän ohjelman, ellet ilmaise selvästi, kuinka muisti omistetaan ja siirretään. C: llä ei ole tällaisia ​​rajoituksia, mutta on viisasta omaksua tuo filosofia ohjaavana valona aina kun mahdollista.

Käytä C-kääntäjävaihtoehtoja, jotka suojaavat muistiongelmilta

Monet tämän artikkelin alkupuoliskolla kuvatuista ongelmista voidaan merkitä käyttämällä tiukkoja kääntäjävaihtoehtoja. Uusimmat versiot gcc, esimerkiksi tarjota työkaluja, kuten AddressSanitizer (“ASAN”) kokoamisvaihtoehtona yleisten muistinhallintavirheiden varalta.

Varoitetaan, nämä työkalut eivät tartu kaikkeen. Ne ovat suojakaiteita; he eivät tartu ohjauspyörään, jos menet maastoon. Jotkin näistä työkaluista, kuten ASAN, asettavat kokoamis- ja ajonaikaisia ​​kustannuksia, joten niitä tulisi välttää julkaisurakenteissa.

Käytä Cppcheckia tai Valgrindia analysoidaksesi C-koodin muistivuotojen varalta

Jos kääntäjät itse jäävät vajaaksi, muut työkalut täyttävät aukon - varsinkin kun on kyse ohjelmakäyttäytymisen analysoinnista ajon aikana.

Cppcheck suorittaa staattisen analyysin C-lähdekoodista etsimään yleisiä virheitä muistinhallinnassa ja määrittelemättömiä käyttäytymismalleja (muun muassa).

Valgrind tarjoaa välimuistin työkaluista muistin ja ketjuvirheiden havaitsemiseen C-ohjelmissa. Tämä on paljon tehokkaampaa kuin kääntöaikaan perustuvan analyysin käyttö, koska voit saada tietoja ohjelman käyttäytymisestä, kun se todella toimii. Haittapuoli on, että ohjelma toimii murto-osalla normaalista nopeudestaan. Mutta tämä on yleensä hieno testaus.

Nämä työkalut eivät ole hopeisia luoteja, eivätkä ne saa kiinni kaikkea. Mutta ne toimivat osana yleistä puolustusstrategiaa C: n muistin huonoa hallintaa vastaan.

Automatisoi C-muistin hallinta roskakorilla

Koska muistivirheet ovat näkyvä C-ongelmien lähde, tässä on yksi helppo ratkaisu: Älä hallitse C-muistia manuaalisesti. Käytä roskien kerääjää.

Kyllä, tämä on mahdollista C.: ssä. Voit lisätä Boehm-Demers-Weiser-roskakorin tapaan automaattisen muistinhallinnan C-ohjelmiin. Joissakin ohjelmissa Boehm-keräilijän käyttö voi jopa nopeuttaa asioita. Sitä voidaan käyttää jopa vuotojen havaitsemismekanismina.

Boehmin roskakorin tärkein haittapuoli on, että se ei voi skannata tai vapauttaa oletusarvoa käyttävää muistia malloc. Se käyttää omaa allokointitoimintoa, ja se toimii vain muistilla, jonka varaat nimenomaan sen kanssa.

Älä käytä C: tä, kun toinen kieli toimii

Jotkut ihmiset kirjoittavat kirjaimella C, koska he nauttivat siitä aidosti ja pitävät sitä hedelmällisenä. Kaiken kaikkiaan on kuitenkin parasta käyttää C: tä vain silloin, kun sinun täytyy, ja sitten vain säästeliäästi, harvoissa tilanteissa, joissa se on todella ihanteellinen valinta.

Jos sinulla on projekti, jonka suorittamisen suorituskykyä rajoittaa lähinnä I / O- tai levykäyttö, sen kirjoittaminen C-muotoon ei todennäköisesti tee sitä nopeammin sillä merkityksellisillä tavoilla, ja todennäköisesti tekee siitä vain virhealttiinta ja vaikeaa ylläpitää. Sama ohjelma voidaan hyvin kirjoittaa Go- tai Python-muodossa.

Toinen lähestymistapa on käyttää C: tä vain todella suorituskykyiselle osat sovelluksen ja luotettavampi, vaikkakin hitaampi kieli muille osille. Jälleen Pythonia voidaan käyttää C-kirjastojen tai mukautetun C-koodin käärimiseen, joten se on hyvä valinta kattilakomponenteille, kuten komentorivivaihtoehtojen käsittelylle.