[PATCH] Implement nonnull-attribute sanitizer
Richard Smith
richard at metafoo.co.uk
Tue Aug 26 20:44:50 PDT 2014
================
Comment at: tools/clang/lib/CodeGen/CGCall.cpp:2414-2415
@@ +2413,4 @@
+ unsigned ParmNum) {
+ if (!CGF.SanOpts->NonnullAttribute || !FD || ParmNum >= FD->getNumParams())
+ return;
+ const NonNullAttr *NNAtt = FD->getAttr<NonNullAttr>();
----------------
samsonov wrote:
> rsmith wrote:
> > What should happen here:
> >
> > __attribute__((nonnull)) void f(const char *, ...);
> > int main() { void *p = 0; f("%s", p); }
> >
> > (I have no idea if the attribute applies in this case.)
> Neither am I :( GCC docs say that "If no argument index list is given to the nonnull attribute, all pointer arguments are marked as non-null", but it's not clear if it refers to call arguments, or formal parameters. What is worse, GCC and Clang seem to disagree on this:
> $ cat tmp/ubsan/bad.cpp
> __attribute__((nonnull)) void *foo2(int *a, ...);
>
> void bar() { foo2(0, (void*)0); }
> $ g++ -Wnonnull -Wall tmp/ubsan/bad.cpp -c -o /dev/null
> tmp/ubsan/bad.cpp: In function ‘void bar()’:
> tmp/ubsan/bad.cpp:3:30: warning: null argument where non-null required (argument 1) [-Wnonnull]
> void bar() { foo2(0, (void*)0); }
> ^
> tmp/ubsan/bad.cpp:3:30: warning: null argument where non-null required (argument 2) [-Wnonnull]
> $ ./bin/clang++ -Wnonnull -Wall tmp/ubsan/bad.cpp -c -o /dev/null
> tmp/ubsan/bad.cpp:3:30: warning: null passed to a callee which requires a non-null argument [-Wnonnull]
> void bar() { foo2(0, (void*)0); }
> ~ ^
> 1 warning generated.
>
> Sigh. Should Clang strive for GCC-compatible behavior, or you have the idea of which behavior is "more predictable" in this case?
I think the GCC behavior makes more sense. We should fix the frontend to also understand this, and model it properly in the AST. Our current representation doesn't work.
================
Comment at: tools/clang/lib/CodeGen/CGCall.cpp:2422
@@ +2421,3 @@
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+ assert(RV.isScalar());
+ llvm::Value *V = RV.getScalarVal();
----------------
samsonov wrote:
> rsmith wrote:
> > What guarantees this? I don't see where you're checking that the parameter is of a pointer type.
> This seems to be handled by Sema:
>
> tmp/ubsan/bad.cpp:1:33: warning: 'nonnull' attribute only applies to pointer arguments [-Wignored-attributes]
> void foo(int *a, __attribute__((nonnull)) int b);
> ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
>
I was thinking about this case:
void f(non_scalar_type x) __attribute__((nonnull));
void g() { f(x); }
... but it looks like the attribute handling flattens the attribute into a list of parameters when it's applied. That's broken in several ways, alas. For instance, we fail to diagnose this properly:
template<typename T> __attribute__((nonnull)) void f(T t);
void g() { f((void*)0); }
... because we can't preserve that we had a parameter-less nonnull attribute until we get to template instantiation.
http://reviews.llvm.org/D5082
More information about the cfe-commits
mailing list