Kun Delphi-kirjasto kasvattaa käännöskonfiguraation ilman visuaalista kehystä, korvaavat luokat ovat se, jossa virheet asuvat. Ei alusta, ei kääntäjä: sijaiset. PDFlibPasilla on grafiikkakerros, joka tarjoaa bittikartan, piirtopinnan, fontin, metafilen ja tulostimen vastineet käännöksille ilman VCL:ää, ja sen porttaaminen Free Pascalille toi esiin jokaisen vikamuodon, jonka sijainen voi saada. Ne järjestäytyvät siististi diagnoosikustannuksen mukaan, ja järjestys on vastakohta sille, mitä intuitio ehdottaa
Sijainen, joka heittää, on halpa löytää; poikkeus nimeää metodin. Sijainen, joka palauttaa tyhjää dataa, on kallis, koska vika ilmenee useita kerroksia syystään etäämpänä. Sijainen, joka palauttaa menestyksen, on kaikkein pahin, koska paluukoodi on pätevä, virhekoodi on nolla, mitään poikkeusta ei heitetä, ja ainoa näyttö siitä, että jokin meni pieleen, on tulleissa tavuissa
Muoto kolme: pätevä kuvatunniste tyhjän XObjectin yllä
Vektori-metafile-muunnin oli tyhjä proseduurirunko ei-VCL-konfiguraatiossa. Kaikki sen yläpuolella jatkoi toimimista. EMF-tuonnin sisääntulopisteet ja piirtopinnankaappaussisääntulopiste ajoivat loppuun asti ja palauttivat laillisen kuvatunnisteen, jonka kutsuja sitten sijoitti sivulle. Tiedostoon päätyi lomake-XObject, jonka sisältöpituus oli nolla. Sivu renderöityi valkoisena
Mikään ei raportoinut ongelmaa, ja siihen lukeutuu kirjaston oma demo-ohjelma tästä ominaisuudesta, joka piirsi tyhjän sivun eikä huomannut. Ei ollut epäonnistuvaa paluuarvoa tarkistettavana, koska kutsujono todella kaikki onnistuivat; ainoa väärässä ollut asia oli tuotetun virran koko. Tämän virheluokan diagnosointi tarkoittaa eri kysymyksen esittämistä: ei ”epäonnistuiko kutsu” vaan ”onko artefakti uskottava”. Nollan pituinen lomake-XObject, nollan pikselin kuva, nollan sisältötavun sivu – nämä ovat assertiot, jotka nappaavat sen
Korjauksella on kaksi puoliskoa, ja toinen puolisko on helppo unohtaa. Ensiksi, tee tyhjästä toteutuksesta heittävä, jotta vialla on kanava ylipäätään. Toiseksi, muunna tuo poikkeus null-tulokseksi kuvatehtaassa ja lisää null-tarkistukset kahteen paikkaan, jotka kuluttavat kuvatunnisteen, koska muuten ”siisti vika” muuttuu suoraan pääsyrikkomukseksi, kun sivupuu dereferoi ei mitään. Heittävä stub on parannus vain, jos kutsujat olivat valmistautuneita vikaan, jota he eivät olleet aiemmin voineet vastaanottaa
Muoto kaksi: tyhjää dataa, kolme kerrosta kaatumisesta
Metafile-piirtopinnan sijainen ei täyttänyt fyysisiä ulottuvuuksiaan. Tuo arvo jakautuu sivugeometrian laskelmaan, joten laskelma tuotti nollan, joten rajauslaatikon laskenta jakoi nollalla. Alaston poikkeuskäsittelijä nielaisi sen, kuvatehdas palautti null-tuloksen, ja pääsyrikkomus tapahtui lopuksi sivupuussa, kun nullia käytettiin. Kolme kerrosta syyn ja oireen välillä, poikkeuskäsittelijä keskellä pyyhkimässä näyttöä
Samalla yksiköllä oli kaksi muuta esiintymää samasta mallista. Fonttiluokalla oli tyhjät Assign- ja konstruktorirungot, mikä merkitsee enemmän kuin näyttää, koska piirtopinnan fonttiominaisuus on vain luku -tyyppinen: siihen sijoittaminen on ainoa tapa toimittaa fontti, joten tyhjä toteutus tekee fontin valinnan hiljaisesti tehottomaksi ja teksti tulee ulos siinä, mikä oletus oli. Ja nollan pikseliä tuumaa kohti -arvo sai jokaisen piirtopintaa fonttimetriikoista koon kutsujan tuottamaan nolla kertaa nolla -piirtopinnan, mikä antaa tyhjän sivun ja menestyksen palautuksen
// Muoto, jota etsitään sijaisyksiköstä: metodi, joka ei tee mitään
// eikä heitä. Molemmat kääntyvät ja molemmat tuottavat ”menestyksen”
// ilman tulostetta
procedure TMetafileCanvasStandIn.Create(...);
begin
// ei inherited-kutsua, ei kenttäalustusta
end;
function TBitmapStandIn.LoadFromStream(Stream: TStream): Boolean;
begin
Result := True; // ja bittikartta on yhä tyhjä
end;
Leveä rakenne, joka säilyttää vain ensimmäisen merkin
Tämä ei ole ylipäätään sijaisongelma, mutta se kuuluu samaan luetteloon, koska oire on yhtä kaukana syystä. Tulostinluettelointirakenne julistettiin kaikkien kahdentoista string-jäsenensä olevan osoittimia yksitavuisiin merkkeihin, kun taas sitä täyttävä funktio on luettelointi-API:n leveämerkkinen variantti
Osoitinkoot ovat identtiset, joten rakenteen asettelu on oikein eikä mikään kaadu. Sen sijaan tapahtuu se, että UTF-16-merkkijonon lukeminen yksitavuisena merkkijonona pysähtyy ensimmäiseen nollatavuun, joka millä tahansa ASCII-tulostimella on toisen merkin ylempi puolikas. Jokainen tulostinnimi palasi täsmälleen yhtenä merkkinä. Alavirrassa nimivalidointi epäonnistui, tulostimen luonti epäonnistui ja tulostaminen epäonnistui jokaiselle koneen todelliselle tulostimelle, eikä mikään niistä oireista osoita rakennedeklaraatioon
// Väärin: oikea koko, väärä elementtityyppi. Ei käännösvirhettä, ei kaatumista,
// jokainen merkkijono katkaistuna yhteen merkkiin
type
TPrinterInfo2Wrong = record
pServerName: PAnsiChar;
pPrinterName: PAnsiChar;
// ... kymmenen muuta
end;
// Oikein: *W-rakenteella on leveät jäsenet läpi
type
TPrinterInfo2W = record
pServerName: PWideChar;
pPrinterName: PWideChar;
// ... kymmenen muuta
end;
Siitä syntynyt sääntö on mekaaninen ja sen soveltaminen kannattaa ajattelematta: mille tahansa Win32-rakenteelle, jonka nimi päättyy W:hen, tarkista, että jokainen merkkijonojäsen on leveä variantti, kenttä kentältä. ANSI:n ja leveän maailman sekoittaminen ei tuota kääntäjädiagnostiikkaa eikä kaatumista, vain hiljaista katkaisua, ja sama pätee käänteisesti ANSI-variaanteihin
Alaston poikkeuskäsittelijä on todellinen vastustaja
Jokainen näistä tutkimuksista hidastui samalla rakenteella: käsittelijällä, joka nappaa kaiken ja muuntaa sen epätodeksi paluuarvoksi. Se on kohtuullinen asia kirjoittaa kuvadekooderin ympärille, koska vioittunut kuva ei saa kaataa dokumenttityötä. Se on myös laite sen ainoan tiedon poistamiseen, jota tarvitset
Käytännön vastaus on tehdä käsittelijästä väliaikaisesti äänekäs. Poikkeusluokan, viestin ja pinovedon vedostaminen alastoman käsittelijän sisältä debug-ehdollisen alla muuntaa selittämättömän null-paluun nimetyksi poikkeukseksi sijainnilla. Kahdessa kolmesta yllä olevasta tapauksesta se yksittäinen askel päätti tutkimisen, koska poikkeus oli nollalla jako tai pääsyrikkomus sijaismetodissa, jonka nimi sanoi kaiken
Tarkistusluettelo sijaispolun omaksumiseen
Neljä kohtaa siinä järjestyksessä, jossa ne kannattavat. Ennen kuin kutsut korvaavaan luokkaan, lue metodit, joita olet käyttämässä, ja varmista, että jokaisella on aito runko; tyhjä runko ei ole toteutuksen yksityiskohta, se on puuttuva ominaisuus. Suosi heittäviä sijaisia neutraaleja arvoja palauttavien sijaan, ja parita se null-tarkistuksilla niissä paikoissa, joissa tehdas voi nyt laillisesti palauttaa ei mitään. Varmista ominaisuus tutkimalla artefaktia, ei paluukoodia, koska koko vikamuoto tässä on siisti paluukoodi tyhjän artefaktin yllä; dokumentin todellisen sisällön tavutason erittely on nopein tapa nähdä se, ja artikkeli tiedostokoon auditoinnista kattaa kyseisen työkalut. Ja kun ominaisuudella ei ole toimivaa korvaavaa toteutusta, ohjaa kyseiset esimerkit polulle, joka toimii, ja sano miksi kommentissa, sen sijaan että jättäisit esittelyn, joka hiljaa tuottaa tyhjää tulostetta
Laajempi pointti pätee paljon kauemmas kuin yhteen kirjastoon. Mikä tahansa koodikanta, jossa on ehdollinen toinen toteutus, mock-kerros, headless-tila tai alustashim, on altis muodolle kolme. Syy siihen, että se piiloutuu niin hyvin, on se, että jokainen laatupiste, johon tiimi yleensä tukeutuu – paluukoodit, virhekoodit, poikkeukset, poistumistilat – on tilakanava, ja muoto kolme pitää ne kaikki puhtaina. Vain tuloste pettää sen. Tuo on myös perustelu sille, että artefakteja tarkistetaan tilojen sijaan käsiteltäessä luotamatonta syötettä, mistä kerrotaan artikkelissa luotamattoman PDF:n jäsentämisestä, ja sille, että renderöityä tulostetta verrataan moottorien välillä yhden luottamisen sijaan, mistä kerrotaan artikkelissa monimoottorinen renderöinti
PDFlibPas on natiivi Object Pascal -PDF-kirjasto Delphille, C++Builderille ja Free Pascalille, ja sen ei-VCL-konfiguraatio on se, mikä tekee headless- ja työkaluketjujen yli ulottuvista käännöksistä mahdollisia; nykyinen konfiguraatiokattavuus on lueteltu losLab PDF Developer Library -tuotesivulla