Bug 17308 - nonnull attribute not as useful as it could
Summary: nonnull attribute not as useful as it could
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 3.4.1
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 22179 30043 46936 (view as bug list)
Depends on: 16361
Blocks:
  Show dependency treegraph
 
Reported: 2004-09-03 20:03 UTC by Ulrich Drepper
Modified: 2015-07-25 20:04 UTC (History)
10 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2005-11-15 16:26:01


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ulrich Drepper 2004-09-03 20:03:03 UTC
The nonnull function attribute seems to recognize only null values which are
explicitly passed to the marked function.  It would be helpful if deduced values
are also reported.  Example:

void *f(void *p) __attribute__((nonnull(1)));
void *bar(void *p)
{
  if (p == (void *) 0) return f(p);
  return p;
}

There compiler knows that p is NULL in the call of f.  The generated code proves
it.  Still no warning.

I see the same behavior with gcc 3.5.
Comment 1 Andrew Pinski 2004-09-03 20:10:17 UTC
I think the issue here is that we issue the warning way before getting to the middle-end, in the front-
end.
Comment 2 Andrew Pinski 2005-06-24 23:13:09 UTC
*** Bug 22179 has been marked as a duplicate of this bug. ***
Comment 3 Andrew Pinski 2008-04-25 20:52:33 UTC
*** Bug 30043 has been marked as a duplicate of this bug. ***
Comment 4 thutt 2008-12-23 15:40:53 UTC
/*
  I concur with Ulrich, but three years on, using gcc 4.1.2.

  Although a parameter which is marked with the 'nonnull' attribute
  is demonstrably nonnull, and although the compiler recognizes it is
  specifically NULL, no warning is emitted.

  And, in fact, the compiler can end up generating bad code.

  Using built-in specs.
  Target: x86_64-redhat-linux
  Configured with: ../configure --prefix=/usr --mandir=/usr/share/man  \
    --infodir=/usr/share/info --enable-shared --enable-threads=posix   \
    --enable-checking=release --with-system-zlib --enable-__cxa_atexit \
    --disable-libunwind-exceptions --enable-libgcj-multifile           \
    --enable-languages=c,c++,objc,obj-c++,java,fortran,ada             \
    --enable-java-awt=gtk --disable-dssi --enable-plugin               \
    --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre           \
    --with-cpu=generic --host=x86_64-redhat-linux
  Thread model: posix
  gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)



        gcc -c  -o nonnull.o -O3 -Wall nonnull.c
        nonnull.c: In function ‘f1’:
        nonnull.c:52: warning: null argument where non-null required (argument 1)
        nonnull.c:52: warning: null argument where non-null required (argument 2)

        objdump --disassemble --reloc nonnull.o

        nonnull.o:     file format elf64-x86-64

        Disassembly of section .text:

        0000000000000000 <f1>:
           0:	f3 c3                	repz retq
           2:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)
           9:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

  If '-Wall' is not provided, the compiler does not even warn about
  the NULL arguments.  It hardly matters if the compiler warns or not,
  the code that is generated for 'f1()' is simply bad code.  But, when
  no warning is provided by the compiler, the code is egregiously bad
  -- anyone wondering why their program doesn't work may disassemble
  the object module and see that nothing was emitted.

        0000000000000010 <f0>:
          10:	ba 00 04 00 00       	mov    $0x400,%edx     ; length = 1024
          15:	31 f6                	xor    %esi,%esi       ; second arg = NULL
          17:	bf 00 00 00 00       	mov    $0x0,%edi       ; first arg = buf
          1c:	48 c7 05 00 00 00 00 	movq   $0x0,0(%rip)    ; a = buf
          23:	00 00 00 00
          27:	48 c7 05 00 00 00 00 	movq   $0x0,0(%rip)    ; b = NULL
          2e:	00 00 00 00
          32:	e9 00 00 00 00       	jmpq   memcpy

  In this function, the compiler has automatically inlined
  'copy_block()', and obviously determined that the second parameter
  is NULL, as can be seen from addresses 15 & 27 -- but still no
  warning is presented.
 */

#include <stdlib.h>
#include <string.h>

extern void *a;
extern void *b;

static void __attribute__((nonnull(1, 2)))
copy_block(void *dest, void *src)
{
   memcpy(dest, src, 1024);
}


void f0(void)
{
   static char buf[100];
   a = buf;
   b = NULL;
   copy_block(a, b);
}

void f1(void)
{
   copy_block(NULL, NULL);
}

Comment 5 Martin Sebor 2010-02-15 20:51:11 UTC
I second Ulrich's request.

Besides nonnull, this enhancement would be useful in attribute printf
as well. For example, in the program below, both calls to printf() have
undefined behavior in C99 and should be diagnosed:

$ cat t.c && gcc -Wformat -pedantic -std=c99 -O3 t.c
int printf(const char*, ...)
  __attribute__((__nonnull__((1))))
  __attribute__ ((__format__ (__printf__, 1, 2)));

int main() {
  char *s = 0;
  printf(s, "");
  printf("%s", s);
}
$
Comment 6 Eric Blake 2011-02-11 16:58:01 UTC
It's been several years, and this attribute is still missing functionality about warning for deduced NULL values.  Can this be looked at?
Comment 7 Manuel López-Ibáñez 2011-02-11 19:43:20 UTC
(In reply to comment #6)
> It's been several years, and this attribute is still missing functionality
> about warning for deduced NULL values.  Can this be looked at?

GCC has as a unwritten policy to not emit warnings from the middle-end, except for a few exceptions. The front-ends do not have the infrastructure to do this kind of analysis, and GCC maintainers have repeatedly said that there is no intention to make gcc front-ends serve as a source code analysis tool like the clang analyzer. So, unless new contributors step forward with a convincing implementation of this, and for what I mean by "convincing" please read point 3 in the notes to beginners[*], the answer is: No, I wouldn't expect this to be implemented in the near or medium future. Sorry for the bad news, but I think it is better to be honest and save you the frustration. 

[*] http://gcc.gnu.org/wiki/GCC_Research
Comment 8 Eric Blake 2012-04-25 19:31:59 UTC
I hit this again today, and I'm still upset that gcc is doing such a poor job with (not) using this attribute as a way to improve code quality via decent warnings.

Basically, libvirt had an issue where we accidentally misused the nonnull attribute marker; we had added the marker in a header file, then later changed the C file to work with a NULL argument but without updating the header file to match: https://bugzilla.redhat.com/show_bug.cgi?id=815270

The calling code managed to pass in a NULL pointer to a parameter based on the semantics we saw in the .c file, but the NULL check in our function in question was "helpfully" elided by gcc since the attribute was still present, all without ever warning us that we were losing the NULL check.  As a result, the code misbehaved when it dereferenced NULL.  If gcc is smart enough to elide code based on the attribute, it should be smart enough to issue a warning that we have dead code, and the only reason the code is assumed to be dead is because of a suspicious attribute.  Had we had the warning, we would have known to either remove our dead NULL check, or to fix the header to no longer have the (now-inappropriate) attribute.

In other words, with a header like:

void foo(void *bar) __attribute__((nonnull(1)));

and a C file like:

void foo(void *bar) { if (!bar) abort(); }

Even if you decide that you are unable to warn about a call to foo(var) because the only way to analyze that var might be NULL is in the middle end but the warning is only emitted by the front end, AT LEAST you could have warned that the 'if (!bar)' conditional is assumed to be dead code based on the attribute placed on var.
Comment 9 Manuel López-Ibáñez 2012-04-25 20:00:44 UTC
(In reply to comment #8)
> Even if you decide that you are unable to warn about a call to foo(var) because
> the only way to analyze that var might be NULL is in the middle end but the
> warning is only emitted by the front end, AT LEAST you could have warned that
> the 'if (!bar)' conditional is assumed to be dead code based on the attribute
> placed on var.

GCC does not warn about unreachable code anymore:

http://gcc.gnu.org/ml/gcc-help/2011-05/msg00360.html

Someone would have to contribute a new -Wunreachable-code implementation. I honestly don't know what kind of implementation would be acceptable by GCC maintainers. Maybe one implemented in the FE? If so, it would require exactly the same infrastructure necessary to implement what Ulrich asks for above.

Sorry, comment #7 still applies.
Comment 10 Manuel López-Ibáñez 2015-07-25 20:04:10 UTC
*** Bug 46936 has been marked as a duplicate of this bug. ***