Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Bevezetés
Ezeket az illesztőprogram-fejlesztési irányelveket a Microsoft illesztőprogram-fejlesztői hosszú éveken keresztül fejlesztették ki. Idővel, amikor a vezetők helytelenül viselkedtek, és leckéket tanultak, ezeket a leckéket rögzítették és továbbfejlesztették, hogy ez legyen az útmutatók készlete. Ezeket az ajánlott eljárásokat a Microsoft Surface Hardver csapata használja az egyedi Surface hardverélményt támogató eszközillesztő-kód fejlesztéséhez és karbantartásához.
Mint minden iránymutatás, itt is lesznek jogos kivételek és alternatív megközelítések, amelyek egyformán érvényesek lesznek. Érdemes lehet ezeket az irányelveket beépíteni a fejlesztési szabványokba, vagy használni őket a fejlesztési környezetre és az egyedi követelményekre vonatkozó tartományspecifikus irányelvek elindításához.
Az illesztőprogram-fejlesztők által elkövetett gyakori hibák
I/O kezelése
- Az IOCTL-ekből lekért pufferek elérése a hossz ellenőrzése nélkül. Lásd pufferek méretének ellenőrzésének sikertelenségét.
- Az I/O blokkolásának végrehajtása egy felhasználói szál vagy véletlenszerű szál kontextusában. Lásd Bevezetés a Kernel Dispatcher Objectscímű témakört.
- Szinkron I/O küldése egy másik illesztőprogramnak időtúllépés nélkül. Lásd: I/O-kérések szinkronizálása.
- A neither-io IOCTL-ek használata anélkül, hogy megértenénk a biztonsági következményeket. Lásd a sem pufferelt, sem közvetlen I/O használatát.
- Nem ellenőrzi a WdfRequestForwardToIoQueue visszatérési állapotát, vagy nem kezeli megfelelően a kudarcot, ami elhagyott WDFREQUEST-eket eredményez.
- A WDFREQUEST nem lemondható állapotban tartása az üzenetsoron kívül. Lásd: I/O-üzenetsorok kezelése, I/O-kérelmek végrehajtása és I/O-kérelmek megszakítása.
- A lemondás kezelése a Mark/UnmarkCancelable függvény használatával az IoQueues használata helyett. Lásd: Keretrendszer sorobjektumai.
- Nem tudja, mi a különbség a fájlkezelő törlési és a bezárási műveletek között. Lásd: A tisztítási és a bezárási műveletekkezelésével kapcsolatos hibák.
- Az esetleges rekurziók figyelmen kívül hagyása az I/O művelet befejezésével és a befejezési rutinból való ismételt benyújtással.
- A WDFQUEUE-k energiagazdálkodási attribútumai nem explicitek. Nem dokumentálja egyértelműen az energiagazdálkodási választási lehetőségeket. Ez a hibaellenőrzési 0x9F elsődleges oka: DRIVER_POWER_STATE_FAILURE WDF-illesztőprogramokban. Az eszköz eltávolításakor a keretrendszer az eltávolítási folyamat különböző szakaszaiban törli az IO-t az energiakezeléssel felügyelt és a nem energiakezeléssel felügyelt üzenetsorokból. A nem energiagazdálkodású sorok törlődnek, amikor megérkezik a végső IRP_MN_REMOVE_DEVICE. Ha tehát az I/O nem egy energia felügyelet alatt álló sorban van, akkor célszerű kifejezetten törölni az I/O-t az EvtDeviceSelfManagedIoFlush kontextusában a holtpont elkerülése érdekében.
- Nem követi az IRP-k kezelésére vonatkozó szabályokat. Lásd: A tisztítási és a bezárási műveletekkezelésével kapcsolatos hibák.
Szinkronizálás
- Olyan kód zárolásának megtartása, amely nem igényel védelmet. Ne tartsa zárolva az egész függvényt, ha csak néhány műveletet kell biztosítani.
- Kihívja a zárral rendelkező sofőröket. Ez a holtpontok elsődleges okai.
- Egymással összekapcsolt primitívek használata zárolási séma létrehozásához a megfelelő rendszer helyett olyan zárolási primitíveket biztosított, mint a mutex, a szemaphore és a spinlock. Lásd: Bevezetés a Mutex-objektumokba, Szemafor objektumok és Bevezetés a spin zárakba.
- Spinlock használata, ahol a passzív zár valamilyen típusa megfelelőbb lenne. Lásd: gyors mutexek és őrzött mutexek és eseményobjektumok. A zárolásokkal kapcsolatos további szempontokért tekintse át az OSR-cikket – A szinkronizálás állapota.
- A WDF-szinkronizálási és végrehajtási szintű modell kiválasztása a következmények teljes ismerete nélkül. Lásd: A keretrendszer zárai használata. Hacsak az illesztőprogram nem monolitikus legfelső szintű illesztőprogram, amely közvetlenül kommunikál a hardverrel, kerülje a WDF-szinkronizálást, mivel az rekurzió miatt holtponthoz vezethet.
- A KEVENT, Semaphore, ERESOURCE, UnsafeFastMutex beszerzése több szál kontextusában, kritikus régióba való belépés nélkül. Ez DOS-támadáshoz vezethet, mert egy ilyen zárolást tartalmazó szál felfüggeszthető. Lásd Bevezetés a Kernel Dispatcher Objectscímű témakört.
- A KEVENT kiosztása a szálveremen, és visszatérés a hívóhoz, amíg az ESEMÉNY még használatban van. Általában akkor készül, amikor IoBuildSyncronousFsdRequest vagy IoBuildDeviceIoControlRequestvan használatban. Ezeknek a hívásoknak a hívójának gondoskodnia kell arról, hogy ne lazítsanak a veremről, amíg az I/O-kezelő nem jelzi az eseményt az IRP befejezésekor.
- Határozatlan ideig várakozik a diszpécseri rutinokban. Általában bármilyen várakozás a diszpécser rutinban rossz gyakorlat.
- Az objektum érvényességének helytelen ellenőrzése (ha blah == NULL) a törlés előtt. Ez általában azt jelenti, hogy a szerző nem ismeri teljes mértékben az objektum élettartamát vezérlő kódot.
Objektumkezelés
- WDF-objektumok szülőként való nem explicit kezelése. Lásd: Bevezetés a keretrendszer-objektumokhoz.
- A WDF-objektum WDFDRIVER-hez való szülőbe helyezése ahelyett, hogy olyan objektumra mutat, amely jobb élettartam-felügyeletet biztosít, és optimalizálja a memóriahasználatot. Például egy WDFREQUEST-nek szülője lehet a WDFDEVICE az IOTARGET helyett. Lásd: Általános keretrendszerobjektumok, Keretrendszerobjektumok életciklusának és Keretrendszerobjektumokösszegzése.
- Nem végzi el az illesztőprogramok között elérhető megosztott memóriaerőforrások lefuttatásos védelmét. Lásd ExInitializeRundownProtection függvény.
- A munkaelem hibás újbóli sorba állítása, miközben az előző már a sorban van vagy már fut. Ez akkor lehet probléma, ha az ügyfél feltételezi, hogy minden várólistán lévő munkaelem végrehajtásra kerül. Lásd a keretrendszer munkatárgyainak használatát. A WorkItems sorba állításával kapcsolatos további információkért tekintse meg a DMF_QueuedWorkitem modult a Driver Module Framework (DMF) projektben – https://github.com/Microsoft/DMF.
- Az üzenet közzététele előtt az időzítő várakozik a feldolgozásra. Lásd Időzítők használata.
- Egy munkaelemben olyan műveletet hajt végre, amely blokkolhatja a folyamatot, vagy határozatlan ideig tarthat a befejezése.
- Olyan megoldás tervezése, amely a sorban álló munkaelemek tömegét eredményezi. Ez nem válaszoló rendszerhez vagy DOS-támadáshoz vezethet, ha a rossz ember képes vezérelni a műveletet (például az I/O-t egy olyan illesztőprogramba pumpálja, amely minden I/O-hoz új munkaelemet vár). Lásd: Keretrendszer munkaelemeinek használata.
- Nem biztosítja, hogy a munkaelem DPC-visszahívásai befejeződjenek az objektum törlése előtt. Lásd A DPC-rutinok írásának irányelvei és a WdfDpcCancel függvény.
- Szálak létrehozása munkafeladatok használata helyett rövid időtartamú/nem lekérdezős feladatokhoz. Lásd: rendszermunkaszálak.
- Az illesztőprogram törlése vagy eltávolítása előtt nem biztosítja, hogy a szálak lefutottak és befejeződtek. A szállefuttatás szinkronizálásával kapcsolatos további információkért tekintse meg a Driver Module Framework (DMF) projekt DMF_Thread moduljához kapcsolódó kódot – https://github.com/Microsoft/DMF.
- Egyetlen illesztőprogram használata különböző, de egymástól függő eszközök kezelésére, valamint globális változók használatával az információk megosztására.
Memória
- Ha lehetséges, ne jelölje meg a passzív végrehajtási kódot PAGEABLE-ként. A lapozóillesztő-kód csökkentheti az illesztőprogram kódlábnyomának méretét, így szabadíthat fel rendszerteret más célokra. Legyen óvatos a lapozható kód megjelölésével, amely az IRQL >= DISPATCH_LEVEL értékét emeli, vagy hívható emelt IRQL-nél. Lásd: Mikor kell a kódnak és az adatoknak lapozhatónak lenniük és illesztőprogramok lapozhatóvá tétele és olyan kód észlelése, amely lapozható.
- Ha nagy struktúrákat deklarál a veremben, inkább használja a halmot vagy a tárhelyet. Lásd: A KernelStack használata és System-Space memóriakiosztása.
- A WDF-objektumkörnyezet szükségtelen nullázása. Ez azt jelezheti, hogy nem egyértelmű, hogy a memória mikor lesz automatikusan nullázva.
Általános illesztőprogram-irányelvek
- WDM és WDF primitívek keverése. WDM-primitívek használata, ahol WDF-primitívek használhatók. A WDF primitívek használata megvédi Önt a gotchastól, javítja a hibakeresést, és ami még fontosabb, hordozhatóvá teszi az illesztőprogramot a usermode-ba.
- Az FDO-k elnevezése és szimbolikus hivatkozások létrehozása, ha nincs szükség rá. Lásd a Illesztőprogramok hozzáférésének szabályozásapontot.
- Másolás és beillesztés, valamint GUID-ek és más állandó értékek használata a mintaillesztőkből.
- Fontolja meg az illesztőmodul-keretrendszer (DMF) nyílt forráskódú kódjának használatát az illesztőprogram-projektben. A DMF a WDF bővítménye, amely további funkciókat tesz lehetővé a WDF-illesztőprogram-fejlesztők számára. Lásd a illesztőprogram-modul keretrendszerénekbemutatását.
- A beállításjegyzék használata folyamatközi értesítési mechanizmusként vagy postaládaként. Alternatív megoldásként tekintse meg a DMF-projektben elérhető DMF_NotifyUserWithEvent és DMF_NotifyUserWithRequest modulokat – https://github.com/Microsoft/DMF.
- Feltételezve, hogy a beállításjegyzék minden része elérhető lesz a rendszer korai rendszerindítási fázisában.
- Függőséget vállal egy másik illesztőprogram vagy szolgáltatás terhelési sorrendjén. Mivel a terhelési sorrend az illesztőprogram vezérlésén kívül módosítható, ez azt eredményezheti, hogy az illesztőprogram kezdetben működik, de később kiszámíthatatlan módon meghiúsul.
- A már elérhető illesztőprogram-könyvtárak újrateremtése, mint például a WDF által biztosított PnP támogatás, leírtak szerint a PnP és az energiagazdálkodás támogatása az illesztőprogramban vagy a busz felületében biztosított könyvtárak az OSR cikkben, amely a Buszfelületek használata az illesztőprogramok közötti kommunikációhozrészletezi.
PnP/Power
- Nem PnP-barát módon működik együtt egy másik illesztőprogrammal – nem regisztrál a PnP-eszközök változására vonatkozó értesítésekhez. Lásd: Regisztrálás eszközillesztő-változás értesítésekhez.
- AcpI-csomópontok létrehozása az eszközök számbavételéhez és energiafüggőségek létrehozásához a buszillesztő vagy a rendszer által biztosított szoftvereszköz-létrehozási felületek használata helyett elegáns módon a PNP-hez és az energiafüggőségekhez. Lásd: A PnP és az energiagazdálkodás támogatása a függvényillesztőkben.
- Az eszköz nem letiltható megjelölése – újraindítás kényszerítése az illesztőprogram frissítésére.
- Az eszköz elrejtése az eszközkezelőben. Lásd Eszközök elrejtése a Device Manager-ból című témakört.
- Feltételezve, hogy az illesztőprogram csak az eszköz egy példányához lesz használva.
- Feltételezve, hogy a meghajtó soha nem lesz eltávolítva. Lásd: a PnP-illesztőprogram kiürítési rutinját.
- Nem kezeli a hamis felület érkezési értesítését. Előfordulhat, és az autóvezetőktől elvárják, hogy biztonságosan kezeljék ezt a helyzetet.
- Nem implementálható az S0 tétlen energiaházirendje, amely fontos a DRIPS-korlátozásokat vagy azok gyermekeit érintő eszközök esetében. Lásd a Készenléti lekapcsolás támogatását alatt.
- A WdfDeviceStopIdle visszatérési állapotának nem ellenőrzése WdfDeviceStopIdle/ResumeIdle egyensúlyhiány miatt energiaforrás-szivárgáshoz és végül 9F hibaellenőrzéshez vezet.
- Nem tudja, hogy a PrepareHardware/ReleaseHardware többször is meghívható az erőforrás-újraegyensúlyozás miatt. Ezeket a visszahívásokat a hardvererőforrások inicializálására kell korlátozni. Lásd: EVT_WDF_DEVICE_PREPARE_HARDWARE.
- A PrepareHardware/ReleaseHardware használata szoftvererőforrások kiosztásához. Az eszközre statikus szoftvererőforrás-foglalást az AddDevice-ben vagy a SelfManagedIoInitben kell elvégezni, ha a hardverrel való interakcióhoz szükséges erőforrások kiosztása szükséges. Lásd: EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT.
Kódolási irányelvek
- Nem használ biztonságos sztring- és egész számfüggvényeket. Lásd: Biztonságos karakterláncfüggvények használata és Biztonságos egész függvények használata.
- Az állandók meghatározásához nem használ típusdefeket.
- Globális és statikus változók használata. Kerülje az eszközönkénti tárolást globális környezetben. A globálisak az információk több eszközpéldányon való megosztására szolgálnak. Alternatív megoldásként fontolja meg a WDFDRIVER objektumkörnyezet használatát az információk több eszközpéldányon való megosztásához.
- Nem használ leíró neveket a változókhoz.
- Nem konzisztens az elnevezési változókban – kis- és nagybetűk konzisztenciája. A meglévő kód frissítésekor nem követi a meglévő kódolási stílust. Például különböző változónevek használata a különböző függvények közös struktúráihoz.
- Fontos tervezési választások nem kommentálása – energiagazdálkodás, zárak, állapotkezelés, munkaelemek, DPC-k, időzítők, globális erőforrás-használat, erőforrás-előfoglalás, összetett kifejezések/feltételes utasítások.
- Megjegyzés azokról a dolgokról, amelyek nyilvánvalóak a meghívott API nevéből. A megjegyzés angol nyelvű megfelelője a függvénynévnek (például a WdfDeviceCreate meghívásakor a "Create the Device Object" megjegyzés írása).
- Ne hozzon létre makrókat, amelyek visszatérési hívással rendelkeznek. Lásd: Függvények (C++).
- Nincsenek vagy hiányos forráskód-széljegyzetek (SAL). Lásd Windows-illesztőprogramok SAL 2.0-s megjegyzései.
- Makrók használata beágyazott függvények helyett.
- Makrók használata állandókhoz constexpr helyett C++ használata esetén
- Az illesztőprogramot fordítsa a C fordítóval, ne a C++ fordítóval, hogy biztosítsa az erős típusellenőrzést.
Hibakezelés
- Nem jelenti a kritikus illesztőprogram-hibákat, és kecsesen jelöli az eszközt nem működőképesnek.
- Nem adja vissza a megfelelő NT-hibaállapotot, amely értelmezhető WIN32-hibaállapotra fordít le. Lásd: NTSTATUS-értékek használata.
- Nem használ NTSTATUS-makrókat a rendszerfüggvények visszaadott állapotának ellenőrzéséhez.
- Szükség esetén nem érvényes állapotváltozókra vagy jelzőkre.
- Annak ellenőrzése, hogy a mutató érvényes-e, mielőtt hozzáférünk hozzá, hogy elkerüljük a versenyfeltételekből adódó problémákat.
- NULL mutatóval való ellenőrzés. Ha null mutatóval próbál hozzáférni a memóriához, a Windows hibaellenőrzést fog végezni. A hibaellenőrzés paraméterei biztosítják a null mutató javításához szükséges információkat. Túlóra, amikor sok szükségtelen ASSERT utasítást adnak hozzá a kódhoz, memóriát használnak fel, és lelassítják a rendszert.
- ÉRVÉNYESÍTÉS az objektumkörnyezet mutatóján. Az illesztőprogram-keretrendszer garantálja, hogy az objektum mindig a környezettel együtt lesz foglalva.
Nyomkövetés
- Nem definiálja a WPP egyéni típusait, és nem használja nyomkövetési hívásokban az emberi olvasható nyomkövetési üzenetek lekéréséhez. Lásd: WPP-szoftverkövetés hozzáadása Windows-illesztőhöz.
- Nem használ IFR-nyomkövetést. Lásd Az Inflight Trace Recorder (IFR) használata a KMDF-ben és az UMDF 2 illesztőprogramokban.
- A függvénynevek megjelenítése a WPP-nyomkövetési hívásokban. A WPP már nyomon követi a függvényneveket és a sorszámokat.
- Nem használ ETW-eseményeket a teljesítmény és az eseményeket befolyásoló egyéb kritikus felhasználói élmény mérésére. Lásd: Eseménykövetés hozzáadása Kernel-Mode illesztőprogramokhoz.
- Nem jelenti a kritikus hibákat az eseménynaplóban, és finoman nem működőképesként jelöli meg az eszközt.
Ellenőrzés
- A fejlesztés és tesztelés során nem futtatja a szabványos és a speciális beállításokkal rendelkező illesztőprogram-ellenőrzőt. Lásd: Illesztőprogram-ellenőrző. A speciális beállításokban ajánlott minden szabályt engedélyezni, kivéve az alacsony erőforrás-szimulációhoz kapcsolódó szabályokat. Célszerű az alacsony erőforrás-szimulációs teszteket külön-külön futtatni, hogy megkönnyítse a hibák hibakeresését.
- A DevFund-teszt nem fut az illesztőprogramon vagy azon eszközosztályon, amelynek az illesztőprogram része, amikor a speciális ellenőrző beállítások engedélyezve vannak. Lásd a DevFund-tesztek futtatása parancssori módban.
- Nem ellenőrzi, hogy az illesztőprogram HVCI-kompatibilis-e. Lásd: HVCI-kompatibilitási kód implementálása.
- Nem futtatják az AppVerifier WUDFhost.exe-n a felhasználói módú illesztőprogramok fejlesztése és tesztelése során. Lásd: Application Verifier.
- Ne ellenőrizze a memóriahasználatot a !wdfpoolusage hibakeresőbővítménnyel futásidőben, hogy a WDF-objektumok ne legyenek elhagyva. A memória, a kérések és a munkaelemek gyakori áldozatai ezeknek a problémáknak.
- Ha nem használja a !wdfkd hibakereső bővítményt, ellenőrizze az objektumfát, hogy meggyőződjön arról, hogy az objektumok megfelelően vannak-e fölérendelve, és ellenőrizze a főbb objektumok(például WDFDRIVER, WDFDEVICE, IO) attribútumait.