"
Static analyzers can only make a single pass through a looping
construct, so they test everything within the block against the
initializations prior to the block.
"
Gonna disagree on this one. Prefast (at least the one I use internally)
does show its progress multiple times through the loop. If prefast
doesn’t know that rcb->nbl isn’t null, it won’t know that “prev” isn’t
null the next time around.
You can determine if this is the case by seeing if this fixes the problem:
__analysis_assume(rcb->nbl != NULL);
It helps to think in terms of local analysis: What CAN Prefast know.
The value of its output is limited by the value of its input.
I tend to prefer __analysis_assume() in my code over #pragma prefast (
suppress: XXX ) because a programmer can easily sanity check the
expression. And I tend to prefer these solutions to doing nothing,
because… generally, Prefast is probably right and I’m probably wrong.
Thanks,
Daniel
On 2/16/2010 5:49 PM, Peter W. Morreale wrote:
On Tue, 2010-02-16 at 16:56 -0800, Ray Trent wrote:
> Maybe it’s just me, but how is PreFast supposed to know that rcb->nbl can’t be NULL? It’s just a
> value passed in inside a list, and PreFast is not a global optimizer. If any rcb->nbl in the
> (non-empty) list ever *were* NULL, NET_BUFFER_LIST_NEXT_NBL would, indeed, dereference a NULL
> pointer, as long as it wasn’t the first or last one.
>
That’s right, it can’t. *I* know its not NULL because rcb exists.
(Initialized at driver init, before we go ‘live’)
But PreFast was not complaining about rcb->nbl, it was complaining about
‘prev’, which it rightly (as a static code analyser) could not detect
that prev would be initialized prior to reference.
> (even in the case where it was the first/last one, the call inside the “if(count)” would dereference
> NULL)
>
Nope. Count can only be non-zero if an rcb was pulled from the list
head (incoming), in which case, prev = rcb->nbl = nbl. Read the code
again?
The idea of the code is to create a chained list of net buffer lists,
and pass in a single list to the upper stack for processing. This (I
was told) would be faster than passing up each NBL individually.
The correct mod was to do the if test on prev, since prev is set outside
of the if block. This allows static analysis to pass on the warning
since it will see that prev is set after the if block.
Static analyzers can only make a single pass through a looping
construct, so they test everything within the block against the
initializations prior to the block.
PreFast complained about the line that contains the:
NET_BUFFER_LIST_NEXT_NBL(prev) = rcb->nbl;
^^^^
as it rightly would. Its just a false positive in this case since only
in the case of having another rcb in the list would that line be
executed (nbl would not be NULL).
Best,
-PWM
> Now, perhaps you’re validating elsewhere (in SrRxKeep, perhaps?) that rcb->nbl != NULL… but it
> looks to me like a genuine hole in this function, when considered standalone.
> On 2/16/2010 9:41 AM, Peter W. Morreale wrote:
>
>> On Tue, 2010-02-16 at 12:10 -0500, Thomas F. Divine wrote:
>>
>>> As far as I know it is not a requirement to resolve all PREfast warnings
>>> before making a WHQL submission.
>>>
>>> However, for at least some PREfast"false positives" simple and reasonable
>>> code restructuring can eliminate the warning and, in the long run, make the
>>> code more maintainable.
>>>
>> I don’t believe so in this case, however the routine is included below
>> for commenting enjoyment. The pointer in question is “prev”.
>>
>>
>>> If there are residual"false positives" that you have carefully evaluated,
>>> then there are pragmas that can be applied to suppress the warning. Annotate
>>> the pragma with a short explanation of the reasoning.
>>>
>>>
>> I prefer to not add pragmas for such, but thank you for the suggestion.
>>
>> Best,
>> -PWM
>>
>>
>> /*
>> * SrRxProcess - Process the busy list of incoming frames.
>> * For keep packets, we chain the rcb NBLs together
>> * to send to the upper layers as a single entity.
>> */
>> static VOID
>> SrRxProcess(PADAPTER a, PLIST_ENTRY incoming)
>> {
>> PNET_BUFFER_LIST nbl = NULL;
>> PNET_BUFFER_LIST prev = NULL;
>> PRCB rcb;
>> ULONG count = 0;
>>
>> while(!IsListEmpty(incoming)) {
>> rcb = (PRCB)RemoveHeadList(incoming);
>>
>> /* Decide whether to discard or keep. */
>> if (SrRxKeep(a, rcb)) {
>>
>> SrRxProcessFrame(rcb);
>>
>> /* Chain received packets together. */
>> if (!nbl)
>> nbl = rcb->nbl;
>> else {
>> NET_BUFFER_LIST_NEXT_NBL(prev) = rcb->nbl;
>> }
>> count++;
>> VenetBusyInc(a); /* Decremented in ReturnNetBuf* */
>> prev = rcb->nbl;
>> }
>> else
>> SrRcbPut(a, rcb, TRUE);
>> }
>>
>> if (count) {
>> NET_BUFFER_LIST_NEXT_NBL(prev) = NULL;
>> NdisMIndicateReceiveNetBufferLists(a->adapterHandle, nbl,
>> NDIS_DEFAULT_PORT_NUMBER, count,
>> NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL);
>> }
>> }
>>
>>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
>
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer