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

Ted Kremenek kremenek at apple.com
Thu Dec 4 11:15:12 PST 2008


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