Re: strlen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Jonny,

On 7/7/21 1:36 PM, Jonny Grant wrote:


On 06/07/2021 23:11, Florian Weimer wrote:
* Jonny Grant:

The reason it does not crash appears to be because of this warning
which removes the call to strlen due to the return not being
checked?

GCC uses the information that the argument to strlen cannot be null on
that particular path.

It's a shame GCC doesn't give a warning

It may be GCC is using '__builtin_strlen'

<string.h> marks the param as nonnull. However, I am surprised this does not trigger the GCC warning -Werror=nonnull

[[gnu::nunnull]], aka __attribute__((nonnull)), is only triggered by compile time NULL. That is: passing NULL (either hardcoded or through a macro)

If after optimizations the compiler realizes that an argument is NULL at compile time, it may (but also may not) trigger the warning. However, if you optimize too much, the expression may vanish, and the warning be silenced again. The -fanalyzer option of GCC may (but also may not) realize of more NULL cases.

I managed to trigger the following, but only with '-O0 -fanalyzer':

[[
<source>:17:20: error: use of NULL 's' where non-null expected [CWE-476] [-Werror=analyzer-null-argument]
   17 |     int x = strlen (s);
      |             ~~~~~~~^~~
  'void f(const char*)': events 1-2
    |
    |   16 |     const char *s = NULL;
    |      |                 ^
    |      |                 |
    |      |                 (1) 's' is NULL
    |   17 |     int x = strlen(s);
    |      |             ~~~~~~~~~~
    |      |                   |
| | (2) argument 1 ('s') NULL where non-null expected
    |
In file included from <source>:4:
/usr/include/string.h:385:15: note: argument 1 of 'size_t strlen(const char*)' must be non-null
  385 | extern size_t strlen (const char *__s)
      |               ^~~~~~
]]


It is undefined behavior to pass NULL to a nonnull parameter, and it is a problem that the caller should check before the call. The compiler may warn you of the most obvious ones, but in the end, the responsibility is on the programmer.

See <https://stackoverflow.com/questions/42035769/how-to-generate-warning-of-non-null-argument-for-my-custom-function>.


/* Return the length of S.  */
extern size_t strlen (const char *__s)
      __THROW __attribute_pure__ __nonnull ((1));

Perhaps that is just a macro that is not actually used......

It _is_ being used:

/usr/include$ grep -rn 'define __nonnull' -B3 -A1
x86_64-linux-gnu/sys/cdefs.h-290-/* The nonull function attribute allows to mark pointer parameters which
x86_64-linux-gnu/sys/cdefs.h-291-   must not be NULL.  */
x86_64-linux-gnu/sys/cdefs.h-292-#if __GNUC_PREREQ (3,3)
x86_64-linux-gnu/sys/cdefs.h:293:# define __nonnull(params) __attribute__ ((__nonnull__ params))
x86_64-linux-gnu/sys/cdefs.h-294-#else
x86_64-linux-gnu/sys/cdefs.h:295:# define __nonnull(params)
x86_64-linux-gnu/sys/cdefs.h-296-#endif


If I add another function -Werror=nonnull does give a warning
void test(const char * const p) __attribute__((nonnull));

https://godbolt.org/z/x37sbfWaG

<source>:15:9: error: argument 1 null where non-null expected [-Werror=nonnull]
    15 |     test(NULL);


strlen.c:11:3: warning: statement with no effect [-Wunused-value]
    11 |   strlen (str);
       |   ^~~~~~~~~~~~

https://godbolt.org/z/caoes5nGa

That site probably uses different library headers.

As posted, with Debian's GCC 8.3, I get this for the main function:

main:
	xorl	%eax, %eax
	ret



In that case maybe https://man7.org/linux/man-pages/man3/strlen.3.html should have a "NOTES" section stating something similar to your wording ?

NOTES

The behavior of strlen(NULL) is depends on different things. It may cause a SEGV exception, or the compiler may optimize and remove the code path handling NULL.


I disagree with this. It is likely that the behavior is that, given the current implementation of Linux/GCC/glibc. But it is undefined behavior, and anything can happen. You should just try harder to avoid it, and not rely on any possible outcome of it. GCC people may decide tomorrow to change the behavior to do some more agresive optimizations, and the documentation shouldn't preclude such a thing, as long as it's legal according to the relevant standards, and sane.


Cheers,

Alex


--
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux