Download presentation
Presentation is loading. Please wait.
Published byBerniece Kennedy Modified over 9 years ago
1
Jakob Lichtenberg Software Development Engineer SDV Adam Shapiro Program Manager Donn Terry Software Development Engineer PFD
2
Static analysis tools: What they are Benefits PREfast for Drivers (PFD) Static Driver Verifier (SDV) Summary
3
Compile-time analysis of the source program: Like code inspection, but performed by a tool. Compile-time type-checking a simple example. Looks for violations of well-defined constraints: Procedure contracts or API contracts. Examples of bugs found by Static Analysis: p = NULL; … f(p); f() requires p to be non-NULL Completing the same IRP twice: IoCompleteRequest (IRP); IoCompleteRequest (IRP);...... IoCompleteRequest (IRP); IoCompleteRequest (IRP);
4
Cheap bugs! Rule of thumb “A defect that costs $1 to fix on the programmer’s desktop costs $100 to fix once it is incorporated into a complete program and many thousands of dollars if it is identified only after the software has been deployed in the field.” “Building a Better Bug Trap” – The Economist, June 2003
5
Push-button technology. 100% path coverage: At little cost (let a computer do it) Quickly (minutes or hours versus weeks) Defects are discovered early: Even before device hardware is available Before designing test cases Often while still coding Defect reports are easy to use: A direct reference to the defective path (or point) in the source code reduces cost of debugging
6
The tool builds an abstract model of a driver and exhaustively inspects execution along all paths: The abstract model is simpler: it’s reduced... It’s so much simpler that it’s possible to have it inspected (“simulated”) exhaustively. Over-approximation of the driver: The control part remains the same. All paths are preserved and treated equally. The data state is over-approximated. if argument x is not constrained, assume any value. if (x>0) guards the point of interest, keep track of Boolean (x>0), but not integer value of x: Boolean is simpler than integer. if (x > 0) { IoCompleteRequest (Irp); }
7
Does not replace functional testing. Targets violations of a given set of well-defined constraints. Principal limitations: It doesn’t know about every possible error. Algorithms are based on source code abstraction and heuristics, which results in both false positives and false negatives. It is a useful tool.
8
PREfast For Drivers (PFD): Lightweight and fast (runs in minutes). Easy to use early in development – start early: Use on any code that compiles. Limited to procedure scope. Works on any code, C and C++. Finds many local violations. Static Driver Verifier (SDV): Extremely deep analysis (runs in hours). More useful in the later stages of development: Requires complete driver. Works over the whole driver (inter-procedural). Limited to WDM and KMDF and to C (more planned). Think: Compile –Time Driver Verifier. Finds deep bugs.
9
Easy Reproducibility Hard Depth Driver Verifier Static Driver Verifier PREfast for drivers Hard Ease of Use Complex A problem has been detected and Windows has been shut down to prevent damage to your computer. DRIVER_IRQL_NOT_LESS_OR_EQUAL If this is the first time you've seen this stop error screen, restart your computer. If this screen appears again, follow these steps: Check to make sure any new hardware or software is properly installed. If this is a new installation, ask your hardware or software Manufacturer for any Windows updates you might need. If problems continue, disable or remove any newly installed hardware or software. Disable BIOS memory options such as caching or shadowing. If you need to use Safe Mode to remove or disable components, restart your computer, press F8 to select Advanced Startup Options, and then select Safe Mode Technical information: *** STOP: 0x00000001 (0x0000000,00000002,0x00000000,0x00000000)
10
Fast (2 to 5 times compile time, usually). Finds many “inadvertent” errors and some “hard” ones. Works on code that compiles; doesn’t need to run. Some things it can find: Null pointer and uninitialized variable (along an unusual path) Local leaks (memory and resource) Mismatched parameters Forgot to check result Format/list mismatch Misuse of IRQLs (some) Various special cases that are easily missed (such as Cancel IRQL) Proper use of callback/function pointers
11
void LeakSample(BOOLEAN Option1) { NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { return STATUS_NO_MEMORY; } //... KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS; } //...
12
void LeakSample(BOOLEAN Option1) { NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { return STATUS_NO_MEMORY; } //... KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS; } //... warning 28103: Leaking the resource stored in 'SpinLock:MyLock'.
13
void LeakSample(BOOLEAN Option1) { NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { KeReleaseSpinLock(MyLock, OldIrql); KeReleaseSpinLock(MyLock, OldIrql); return STATUS_NO_MEMORY; } //... KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS; } //…
16
Precisely describe the “part” you’re building and the contract that represents. Enable automatic checking. Tells tools things they can’t infer. Effective (and checked) documentation: Programmers don’t have to guess/experiment. Code and documentation don’t drift apart. Comments are nice, but…
17
Record and express the contract: Developers know what the contract is. Is the contract a good one? Automatic checking: that is, “cheap” bugs: The sooner a bug is found, the less expensive it is to fix. Annotated code finds many more bugs (with less noise) than un-annotated code. Code that enters test with fewer “easy” bugs makes testing far more efficient – less wasted time for finding and fixing easy bugs.
18
wchar_t * wmemset( __out_ecount(s) wchar_t *p, __in wchar_t v, __in size_t s); __in: the parameter is input to the function __out: the parameter is output from the function __out_ecount(s): the parameter is a buffer with s elements If the parameter p doesn’t contain at least s elements, PFD will yield a warning.
19
typedef VOID DRIVER_CANCEL ( __in struct _DEVICE_OBJECT *DeviceObject, __in struct _IRP *Irp ); typedef DRIVER_CANCEL *PDRIVER_CANCEL; wdm.h Driver.h DRIVER_CANCEL MyCancel ; Driver.c VOID MyCancel ( struct _DEVICE_OBJECT *DeviceObject, struct _IRP *Irp ) { … }
20
If your driver uses floating point, you must be very careful to protect the hardware. It’s easy to forget that you used it. It’s very hard to find in test, typically not repeatable, and blue-screen is the preferable symptom. It can span multiple functions.
21
long intSqrt(long i) { return (long) sqrt((double)i); }
22
long intSqrt(long i) { return (long) sqrt((double)i); } … if (KeSaveFloatingPointState(b)) { … intSqrt(…) … KeRestoreFloatingPointState(b); } else // deal with error … intSqrt(…) … …
23
__drv_floatUsed long intSqrt(long i) { return (long) sqrt((double)i); } … if (KeSaveFloatingPointState(b)) { … intSqrt(…) … KeRestoreFloatingPointState(b); } else // deal with error … intSqrt(…) … …
24
Jakob Lichtenberg Software Development Engineer Microsoft Corporation
25
Two complementary technologies provided in the WDK: PREfast for Drivers: Look inside every procedure for possible violations. Static Driver Verifier: Look along paths, cross inter-procedural boundaries. ReadFoo ( PIRP Irp ) { PIRP p = NULL;... if (status) { IoCompleteRequest(p); } ReadFoo ( PIRP Irp ) {... status = Bar (Irp); if (status) { IoCompleteRequest(Irp); } Bar ( PIRP Irp ) {... IoCompleteRequest(Irp); return STATUS_SUCCESS; }XX XX
26
PREfast for Drivers (PFD): Lightweight and fast (runs in minutes). Easy to use early in development – start early. Use on any code that compiles. Limited to a procedure scope; each procedure analyzed independently. Annotations improve precision. Works on any code, C and C++. Finds many local violations. Static Driver Verifier (SDV): Extremely deep analysis (runs in hours). More useful in the later stages of development. Requires complete driver. Works over the whole driver, along every path, crossing inter-procedural boundaries. Annotations not necessary. Limited to WDM or KMDF and to C. Finds a few deep bugs.
27
What Static Driver Verifier does: Global analysis of entire driver. Looks for violations of DDI constraints. SDV for WDM: 68 rules covering aspects such as IRPs, IRQL, Plug and Play, and synchronization rules. New: SDV for KMDF: 52 rules covering aspects such as DDI ordering, device initialization, request completion, and request cancellation. Availability: from Windows Longhorn Server WDK. Limitations: Only pure C drivers. Up to 50 K lines of code.
28
Device Driver Interface IoCompleteRequest Driver Dispatch Routine I/O System Irp Irp Irp
29
Device Driver Interface IoCompleteRequest Driver Dispatch Routine I/O System Irp Irp Irp X X
30
Parport driver sample in Win XP SP1 DDK
31
One defect found One defect found XX
32
First Completion Double Completion
33
Rule Passes Rule Passes Server 2003 SP1 DDK
34
PptDispatchClose ( Irp ) P4CompleteRequest ( Irp ) IoCompleteRequest( Irp );XX PptFdoClose( Irp ) P4CompleteRequestReleaseRemLoc ( Irp ) IOMngr
35
library.c more_code.c driver.c XX SDV
36
SDV Rules Verification Engine OS Model library.c more_code.c driver.c X X
37
SDV Verification Engine OS Model library.c more_code.c driver.c Rules X X
38
Rule 1
39
Rule 2
40
Rule 3
41
SDV comes with: 68 WDM rules 52 KMDF rules Each rule captures an aspect of an interface requirements. Rules are written in a C-like language and define: State declarations in form of C-style variables. Events that are associated with DDI functions.
42
Device Driver Interface KeAcquire SpinLock KeRelease SpinLock Driver Entry Point I/O System
43
Device Driver Interface KeAcquire SpinLock KeRelease SpinLock Driver Entry Point I/O System state { enum {unlocked, locked} s = unlocked; enum {unlocked, locked} s = unlocked;} Abort Acquire Release Driver called Driver returns Unlocked Acquire Driver returns Locked Release
44
Device Driver Interface KeAcquire SpinLock KeRelease SpinLock Driver Entry Point I/O System RunDispatchFunction.exit { if (s != unlocked) abort; if (s != unlocked) abort;} KeAcquireSpinLock.entry { if (s != unlocked) abort; if (s != unlocked) abort; else s = locked; else s = locked;} KeReleaseSpinLock.entry { if (s != locked) abort; if (s != locked) abort; else s = unlocked; else s = unlocked;} state { enum {unlocked, locked} s = unlocked; enum {unlocked, locked} s = unlocked;}
45
SDV Verification Engine library.c more_code.c driver.c Rules OS Model X X
46
Exercises the driver: Calls DriverEntry Calls Dispatch functions Calls ISRs Models certain aspects of the operating system state: Like the current interrupt request level (IRQL) Models device driver interface functions: Like the IoCallDriver DDI Device Driver Interface Driver I/O System
47
Device Driver Interface Driver void main() { int choice, status; … int choice, status; … status = DriverEntry(…); … status = DriverEntry(…); … status = AddDevice(…); … status = AddDevice(…); … … switch (choice) { switch (choice) { case 0: case 0: status = DriverRead(…); status = DriverRead(…); break; break; case 1: case 1: status = DriverWrite(…); status = DriverWrite(…); break; break; … case 28: case 28: status = DriverCreate(…); status = DriverCreate(…); break; break; default: default: status = DriverClose(…); status = DriverClose(…); break; break; }} I/O System CloseCreateWriteRead DriverEntryAddDevice … …
48
Device Driver Interface Driver NTSTATUS IoCallDriver( …, PIRP Irp ) { int choice; int choice; … switch (choice) { switch (choice) { case 0: case 0: … Irp->PendingReturned = 0; Irp->PendingReturned = 0; return STATUS_SUCCESS; return STATUS_SUCCESS; case 1: case 1: … Irp->PendingReturned = 0; Irp->PendingReturned = 0; return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL; default: default: … Irp->PendingReturned = 1; Irp->PendingReturned = 1; return STATUS_PENDING;; return STATUS_PENDING;; }} I/O System IoCallDriver SUCCESS UNSUCCESSFUL PENDING …
49
SDV library.c more_code.c driver.c Rules OS Model Verification Engine X X
50
Executes: Your driver in the context of the operating system model. While keeping track of the rule state. While looking for rule violations. Checks each and every path of the driver. Implements worst-case behavior. Symbolic model checker: Strategy: Throw away many irrelevant details through aggressive, but correct, abstraction. Device Driver Interface Driver I/O System IoCallDriver SUCCESS UNSUCCESSFUL PENDING CloseCreateWriteRead DriverEntryAddDevice … …
51
Device Driver Interface Driver I/O System IoCallDriver SUCCESS UNSUCCESSFUL PENDING CloseCreateWriteRead DriverEntryAddDevice … … ReadWriteCreateClose… SUCCESS … UNSUCCESFUL … PENDING … ……………… XX
52
Comprehensive path coverage: Driver is exercised in a hostile environment. Verifies all possible paths in the drivers. Verifies cross-function calls. Verifies driver together with supporting libraries. But there are places where SDV is imprecise: Only one driver (not the entire driver stack). Operating system model imperfect. The verification engine is not precise.
53
Finds deep bugs not found by testing: 1 bug on average for a sample driver in Server 2003 DDK-3677. Well-tested drivers are often clean. A dozen true bugs in a fresh driver. Low noise level: Less than 1 false bug reported per driver. 2 real bugs for 1 false bug on DDK-3677 samples. Performance: WDM: Runs in a few hours, but may need to run overnight. KMDF: Much, much faster. New: SDV will take advantage of all available CPU cores.
54
The business case: Reduce risk of expensive after- deployment bugs. Reduce time to market. Reduce cost of code review and testing. Improve code quality. Achieve higher test coverage. The development case: Find/prevent bugs earlier. More directly and obviously. Find/prevent “hard- to-test” bugs. Make you more efficient.
55
It doesn’t know about all possible errors. It doesn’t make testing unnecessary. Both false positives and false negatives can be misleading. Static Analysis Tools complement testing.
56
PREfast for DriversStatic Driver Verifier Driver Models AnyWDM KMDF Applicability C and C++C only Issues found Local defects Easy to fix High volume Global defects Harder to fix Low volume Development Cycle Apply early: “When the driver compiles” Run often… Apply later: “When the basic structure of the driver is in place” Run ad hoc or overnight…
57
© 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.