Ko Delphi knjižnica pridobi gradbeno konfiguracijo brez vizualnega ogrodja, so nadomestni razredi tisto, kjer živijo hrošči. Ne platforma, ne prevajalnik: namestitve (stand-ins). PDFlibPas ima grafično plast, ki zagotavlja ustrežnike bitne slike, platna, pisave, metafila in tiskalnika za gradnje brez VCL, in prenos na Free Pascal je površil vsak način odpovedi, ki ga lahko ima namestitev. Razvrstijo se lepo po strošku diagnosticiranja in vrstni red je nasprotje tistega, kar nakazuje intuicija
Namestitev, ki sproži izjemo, je poceni najti; izjema poimenuje metodo. Namestitev, ki vrne prazne podatke, je draga, ker se odpoved pojavi nekaj plasti stran od svojega vzroka. Namestitev, ki vrne uspeh, je najslabša od vseh, ker je povratna koda veljavna, koda napake je nič, nobena izjema ni sprožena in edini dokaz, da je kaj šlo narobe, je v bajtih, ki so prišli ven
Tretji lik: veljaven identifikator slike nad praznim XObjectom
Vektorski pretvornik metafila je bilo prazno telo procedure v ne-VCL konfiguraciji. Vse nad njim je ostalo delovati. Vstopne točke uvoza EMF in vstopna točka zajema platna so tekle do konca in vrnele legalen identifikator slike, ki ga je klicatelj nato postavil na stran. V datoteko je pristal formni XObject z dolžino vsebine nič. Stran se je upodobila bela
Nič ni poročalo o težavi in to vključuje lastni demonstracijski program knjižnice za to funkcijo, ki je narisal prazno stran in tega ni opazil. Ni bilo odpovedane povratne vrednosti za preverjanje, ker je zaporedje klicev resnično vsem uspelo; edino napačno je bila velikost proizvedenega toka. Diagnosticiranje tega razreda napak pomeni zastaviti drugačno vprašanje: ne »ali je klic odpovedal« ampak »ali je artefakt verjeten«. Formni XObject dolžine nič, slika nič pikslov, stran nič bajtov vsebine, to so trditve, ki ga ujamejo
Popravek ima dve polovici in druga polovica je enostavna za pozabo. Najprej naredite prazno implementacijo sprožajočo, tako da odpoved sploh ima kanal. Drugo, pretvorite to izjemo v rezultat null v tovarni slik in dodajte preglede null na dveh mestih, ki porabijo identifikator slike, ker sicer se »čista odpoved« obrne naravnost v kršitev dostopa, ko drevo strani dereferencira nič. Štub, ki meče, je samo izboljšava, če so bili klicatelji pripravljeni na odpoved, ki je prej nikoli niso mogli prejeti
Drugi lik: prazni podatki, tri plasti od sesutja
Namestitev platna metafila ni izpolnila svojih fizičnih mer. Ta vrednost se deli v izračun geometrije strani, zato je izračun proizvedel nič, zato se je izračun omejevalnega okvira delil z nič. Goli ročaj izjem je to pogoltnil, tovarna slik je vrnila rezultat null, kršitev dostopa pa se je končno zgodila v drevesu strani, ko je bila ničla uporabljena. Tri plasti med vzrokom in simptomom, z ročajem izjem na sredini, ki briše dokaze
Ista enota je imela še dva primerka vzorca. Razred pisave je imel prazni telesa Assign in konstruktorja, kar je pomembnejše, kot izgleda, ker je lastnost pisave platna samo za branje: dodeljevanje vanjo je edini način dostave pisave, zato prazna implementacija naredi izbiro pisave tiho neučinkovito in besedilo pride ven v katerem koli privzetem. In vrednost pik na palec nič je naredila vsakega klicatelja, ki dimensionira platno iz metrik pisave, proizvajalca platna nič-krat-nič, kar da prazno stran in uspešen povratek
// Liki, ki ga iskati v namestitveni enoti: metoda, ki ne sproži
// izjeme in ne počne ničesar. Oba se prevodita in oba proizvedeta
// »uspeh« brez izhoda
procedure TMetafileCanvasStandIn.Create(...);
begin
// brez klica inherited, brez inicializacije polj
end;
function TBitmapStandIn.LoadFromStream(Stream: TStream): Boolean;
begin
Result := True; // in bitna slika je še vedno prazna
end;
Široka struktura, ki obdrži samo prvi znak
Ta sploh ni težava namestitve, ampak pripada v isti katalog, ker je simptom enako daleč od vzroka. Struktura številčenja tiskalnikov je bila deklarirana z vsemi dvanajstimi člani nizov tipiziranimi kot kazalce na enobajtne znake, medtem ko je funkcija, ki jo izpolni, različica širokih znakov API-ja številčenja
Velikosti kazalcev so identične, zato je razporeditev strukture pravilna in nič se ne sesuje. Tisto, kar se zgodi namesto tega, je, da branje niza UTF-16 kot enobajtnega niza ustane na prvem ničelnem bajtu, ki je za vsako ime tiskalnika ASCII zgornja polovica drugega znaka. Vsako ime tiskalnika se je vrnilo kot natanko en znak. Nizvodno je validacija imen odpovedala, ustvarjanje tiskalnika je odpovedalo in tiskanje je odpovedalo za vsak pravi tiskalnik na stroju, in noben od teh simptomov ne kaže na deklaracijo strukture
// Napačno: prava velikost, napačen tip elementa. Brez napake
// prevajanja, brez sesutja, vsak niz skrajšan na en znak
type
TPrinterInfo2Wrong = record
pServerName: PAnsiChar;
pPrinterName: PAnsiChar;
// ... še deset
end;
// Pravilno: struktura *W ima široke člane povsod
type
TPrinterInfo2W = record
pServerName: PWideChar;
pPrinterName: PWideChar;
// ... še deset
end;
Pravilo, ki iz tega izhaja, je mehansko in vredno uporabe brez razmišljanja: za vsako strukturo Win32, katere ime se konča na W, preverite, da je vsak član niza široka različica, polje po polju. Mešanje svetov ANSI in širokih ne proizvede niti diagnostike prevajalnika niti sesutja, samo tiho krajšanje, in enako velja v obratni smeri za različice ANSI
Goli ročaj izjem je pravi nasprotnik
Vsaka od teh preiskav je bila upočasnjena s strani istega konstrukta: ročaj, ki ujame vse in to pretvori v povratno vrednost lažno. Je razumna stvar za pisanje okoli dekodirnika slik, ker pokvarjena slika ne bi smela podreti dokumentnega opravila. Je tudi naprava za brisanje enega samega kosa informacije, ki ga potrebujete
Praktični odziv je narediti ročaj začasno glasnega. Odlaganje razreda izjeme, sporočila in sledi (backtrace) iz znotraj golega ročaja, pod pogojnim razhroščevalnim stavkom, pretvori nerazložen povratek null v poimenovano izjemo z lokacijo. V dveh od treh primerov zgoraj je ta en korak končal preiskavo, ker je bila izjema deljenje z nič ali kršitev dostopa v metodi namestitve, katere ime je reklo vse
Kontrolni seznam za sprejetje poti namestitve
Štirje predmeti, v vrstnem redu, v katerem se izplačajo. Pred klicem v nadomestni razred preberite metode, ki jih nameravate uporabiti, in potrdite, da ima vsak pravo telo; prazno telo ni podrobnost implementacije, je manjkajoča funkcija. Dajte prednost namestitvam, ki sprožijo izjemo, pred namestitvami, ki vračajo nevtralne vrednosti, in to sparite s pregledi null na mestih, kjer tovarna lahko zdaj upravičeno vrne nič. Preverite funkcijo z pregledom artefakta, ne povratne kode, saj je celoten način odpovedi tukaj čista povratna koda nad praznim artefaktom; razčlenitev na ravni bajtov tega, kaj dokument dejansko vsebuje, je najhitrejši način, da to vidite, in članek o reviziji velikosti datoteke pokriva to orodje. In ko funkcija nima preživetja sposobne nadomestne implementacije, usmerite prizadete vzorce na pot, ki deluje, in recite zakaj v komentarju, namesto da pustite demonstracijo, ki tiho proizvaja prazen izhod
Širša točka velja daleč onkraj ene knjižnice. Vsaka kodna baza s pogojno drugo implementacijo, plastjo mock, brezglavnim načinom, platformskim šimom, je izpostavljena tretjemu liku. Razlog, zakaj se tako dobro skriva, je, da je vsaka vrata kakovosti, na katera se ekipa običajno zanese — povratne kode, kode napak, izjeme, izstopna stanja — statusni kanal, tretji lik pa vse te obdrži čiste. Samo izhod ga izda. To je tudi utemeljitev za pregledovanje artefaktov namesto stanj pri rokovanju z nezaupanim vhodom, opisano v članku o razčlenjevanju nezaupanega PDF, in za primerjavo upodobljenega izhoda čez motorje namesto zaupanja enemu, opisano v večmotornem upodabljanju
PDFlibPas je lastna PDF knjižnica v Object Pascalu za Delphi, C++Builder in Free Pascal, njegova ne-VCL konfiguracija pa je tisto, kar naredi brezglavne gradnje in gradnje čez orodjarne mogoče; trenutna pokritost konfiguracij je navedena na strani produkta losLab PDF Developer Library