[cfe-dev] NonNull attribute, bug report. (Or misunderstanding)

Ted Kremenek kremenek at apple.com
Thu Dec 4 11:41:07 PST 2008


There indeed was a serious bug in parsing attribute(nonnull), now fixed:

http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20081201/009943.html

Thanks so much for brining this to everyone's attention!

In your code I think if you use zero-based indexing for the arguments  
your test case should work as expected.  Please let us know if it  
doesn't.

On Dec 4, 2008, at 11:15 AM, Ted Kremenek wrote:

> Incidentally, I do think there is a clang bug here in how we process  
> the nonnull attribute.  I'm writing a few more test cases for the  
> analyzer to identify the issue.
>
> On Dec 4, 2008, at 10:39 AM, Ted Kremenek wrote:
>
>>
>> On Dec 4, 2008, at 4:27 AM, Paolo Bolzoni wrote:
>>
>>> Simple declaration:
>>> extern void* my_memcpy (void *dest, const void *src, unsigned long  
>>> len)
>>>    __attribute__((nonnull (1, 2)));
>>>
>>>
>>>
>>> The relative AST vertex do have the clang::Attr pointer. But this  
>>> simple loop
>>> outputs nothing:
>>>
>>> my_decl is a clang::FunctionDecl* relative to the function  
>>> declaration.
>>> non_null_attribute is a clang::NonNullAttr* relative to the non  
>>> null attribute
>>> of my_decl.
>>>
>>> for (unsigned int e = my_decl-> getNumParams(), b = 1; b <= e; + 
>>> +b) {
>>> if (non_null_attribute-> isNonNull(b)) {
>>>   std::cout << "Yes, parameter " << b << "is non-null!" <<  
>>> std::endl;
>>> }
>>> }
>>>
>>> What am I doing wrong? Or there indeed is a clang bug somewhere?
>>
>> Hi Paolo,
>>
>> You should use a zero-indexed numbering of the attributes.  '1' and  
>> '2' getting converted internally to '0' and '1' to match with the  
>> indexing of parameters in the ASTs.
>>
>> It may also be instructive to look at how the static analyzer  
>> consults this attribute (this is in GRExprEngineInternalChecks.cpp):
>>
>>   FunctionDecl* FD =  
>> dyn_cast<FunctionDecl>(cast<loc::FuncVal>(X).getDecl());
>>   const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
>>
>>   if (!Att)
>>     return false;
>>
>>   // Iterate through the arguments of CE and check them for null.
>>
>>   unsigned idx = 0;
>>   bool hasError = false;
>>
>>   for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I! 
>> =E;
>>        ++I, ++idx) {
>>
>>     if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
>>       continue;
>>
>>     RangedBugReport R(BT, N);
>>     R.addRange((*I)->getSourceRange());
>>     Reports.push_back(R);
>>     hasError = true;
>>   }
>>
>> Since this code is so similar to yours, I'm a little confused why  
>> you don't get even one "Yes, parameter X is non-null" anywhere.   
>> One thing worth verifying is that 'e' is non-zero (i.e., is the  
>> look ever entered).  Inserting breakpoints in gdb would be my next  
>> step.
>>
>> There is also a test case for the static analyzer in test/Analysis  
>> that might be useful to compare against:
>>
>> $ cd test/Analysis
>> $ clang -checker-simple null-deref-ps.c
>> ...
>> ANALYZE: null-deref-ps.c f6
>> null-deref-ps.c:64:15: warning: Null pointer passed as an argument  
>> to a 'nonnull' parameter
>> return !p ? bar(p, 1) // expected-warning {{Null pointer passed as  
>> an argument to a 'nonnull' parameter}}
>>             ^   ~
>> ANALYZE: null-deref-ps.c f6b
>> null-deref-ps.c:71:15: warning: Null pointer passed as an argument  
>> to a 'nonnull' parameter
>> return !p ? bar2(p, 1) // expected-warning {{Null pointer passed as  
>> an argument to a 'nonnull' parameter}}
>>             ^    ~
>> ...
>




More information about the cfe-dev mailing list