次の方法で共有


Annotating for __success()

__success() is an annotation that hs been around for "a little while", but isn't widely known about. Admittedly, finding content about it on MSDN is difficult - that should change as we approach the release of Windows 7. Upon release, exposure to the __success() annotation is going to become very common with the release of the Windows 7 WDK: any function that returns NTSTATUS (read: a large majority of Kernel functions we publish in the WDK) will have the __success() annotation appended to it:

 

typedef __success(return >= 0) long NTSTATUS;

 

The annotation carries a dual meaning: to the developer, it is an easy reminder of the return value (or set of return values) that indicate the function was successful. Most NTSTATUS functions return 0 to indicate success, the greater-than or equal sign is present because a select few will return some positive number besides zero to indicate success.  The scanning engine expands on that feeling by assuming that functions annotated with the __success() annotation will only fulfill their contract when returning a value that is considered to be “success”. The following declaration will help demonstrate this meaning:

typedef

__success(return >= 0)

__drv_acquiresGlobalResource(SomeResource)

long

AcqResource (__out int *x);

 

When the scanner is processing a function that calls AcqResource, it will assume that SomeResource is acquired only when the function returns a success status. This follows the a typical coding convention of only doing as the function says when the function is successful; the annotation is a strict reinforcement of that principle. When the __success() annotation is not included, the scanner will always assume that the resource is acquired. There is one caveat to keep in mind: if x was notinitialized before this call, the __out annotation stipulates that it will be initialized after this call, successful or not. When dealing with the fail case, it is common that a fail status from the function means the failure to acquire the resource. Whether or not the parameter is initialized post-call is a scenario of great debate, so the scanner assumes it was somehow initialized. The best way to deal with this confusion? Initialize the variable when you declare it, always a good idea in practice anyway.

 

Suppose, however, you have another function where you wish to express that an __out parameter would be returned to the caller as NULL in the case where the function failed. The annotation __on_failure() exists for this reason, to be explained following this example:

 

typedef

__success (return >= 0)

__drv_acquiresGlobalResource(SomeResource)

long

AcqResourceAndX( __out __on_failure(__null) int* x)

 

                The __on_failure(__null) annotation states that on function exit, when the return value is less than 0 (__on_failure), assume that the value of x (the address at which the value accessed by *x is found) is null. You may find that within your own coding style, __out parameters are always null or otherwise invalid in a fail case, and wonder why the scanner cannot go figure that out for itself. Remember that the PFD scanner only deals with a function at a time, and has to rely solely on the annotations for information concerning a call within that function. So while you may have code that obviously would set x to null on the failure instance, PFD will not know that unless you tell it specifically.

Comments