This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/17365] New: degenerate string.h operations not optimised to no-ops, and can cause compiler warnings


https://sourceware.org/bugzilla/show_bug.cgi?id=17365

            Bug ID: 17365
           Summary: degenerate string.h operations not optimised to
                    no-ops, and can cause compiler warnings
           Product: glibc
           Version: 2.19
            Status: NEW
          Severity: minor
          Priority: P2
         Component: libc
          Assignee: unassigned at sourceware dot org
          Reporter: pc+sourceware at asdf dot org
                CC: drepper.fsp at gmail dot com

For example, in <bits/string2.h> there are macros like this:

#  define strncat(dest, src, n) \
  (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n)      \
                  ? (strlen (src) < ((size_t) (n))                            \
                     ? strcat (dest, src)                                     \
                     : strncat (dest, src, n))                                \
                  : strncat (dest, src, n)))

With gcc -Wtype-limits, src being a string string literal, and - most
importantly - n being 0, the above can cause compiler diagnostics like:

warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
                  ? strlen (src) < ((size_t) (n)))) 

Of course, with n==0, the operation is a no-op. Therefore the macros could make
that explicit, to take the responsibility off the compiler for noticing such
shortcuts.

That particular case may sound contrived, but other examples that have the same
issue can easily crop up in real world code, such as strncmp(var,
LITERAL_STRING, sizeof(LITERAL_STRING)-1) where LITERAL_STRING is "".

Alas, even optimising the macro to make it do nothing in the n==0 case doesn't
fix the warnings, as gcc pedantically checks all subexpressions for silliness
even if they can not be evaluated. (To be honest it's the warnings that are
more annoying than the lack of optimisation, as the compiler will almost
certainly optimise the expression to nothing.)

The issue is old - here's an example from a 32-bit glibc 2.11 installation:

baz$ cat > strncmp.c
#include <string.h>
static const char magic[] = "";
int foo(const char *s) {
        return strncmp(s, magic, sizeof(magic)-1);
}

baz$ gcc -Wtype-limits -O -o strncmp.o -c strncmp.c
strncmp.c: In function 'foo':
strncmp.c:4: warning: comparison of unsigned expression < 0 is always false

baz$ gcc -v
...
gcc version 4.4.5 (Debian 4.4.5-8) 

Another, 64-bit x86_64 with glibc 2.13:

bar$ gcc -Wtype-limits -O -o strncmp.o -c strncmp.c
strncmp.c: In function 'foo':
strncmp.c:4:9: warning: comparison of unsigned expression < 0 is always false
[-Wtype-limits]
strncmp.c:4:9: warning: comparison of unsigned expression < 0 is always false
[-Wtype-limits]

bar$ gcc -v
gcc version 4.7.2 (Debian 4.7.2-5) 

And others. I.e. it will occur pretty much no matter the glibc version (2.11,
2.13, 2.19 tested), the arch (x86, x86_64, ppc tested), or the gcc version
(4.4, 4.7, and 4.9 tested). (As long as the compiler actually performs the
substitutions in the macros in your header files. With some compiler settings,
it uses a compiler-builtin <string.h> and ignores your header files. Running
gcc through ccache seems to stops gcc from using its own builtin headers.). All
that matters is that it expands an ``strlen(s) < ((size_t) (n))'' construct.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]