Re: strlen

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

 




On 05/09/2020 08:12, Florian Weimer wrote:
> * Jonny Grant:
> 
>> On 04/09/2020 20:21, Florian Weimer wrote:
>>> * Jonny Grant:
>>>
>>>> Hello
>>>>
>>>> https://man7.org/linux/man-pages/man3/strlen.3.html
>>>>
>>>> Is it possible to clarify :-
>>>>
>>>> * glibc will SIGSEGV if 's' is NULL
>>>> * there are no ERROR returns
>>>
>>> That would be misleading.  Whether strlen (NULL) is undefined also
>>> depends on the compiler.  They know that the argument cannot be zero
>>> and optimize accordingly.
>>>
>>
>> Hi,
>>
>> Do you know a compiler that has a different behaviour? I only tested
>> gcc and clang. How would a compiler optimise?
> 
> Here's an example:
> 
> #include <stddef.h>
> #include <stdio.h>
> #include <string.h>
> 
> void
> f (const char *str)
> {
>   strlen (str);
>   if (str == NULL)
>     puts ("str is NULL");
> }
> 
> int
> main (void)
> {
>   f (NULL);
>   return 0;
> }
> 
> When built with -O2, GCC 8 prints nothing, and there is no crash.
> 
> My point it's not just the C *library* that makes strlen (NULL)
> undefined.  It's undefined according to the language, and even if we
> changed the glibc implementation, things would still go wrong.
> 

Hi Florian, Apologies for tardy response time.

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?

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

https://godbolt.org/z/caoes5nGa


.LC0:
        .string "str is NULL"
f(char const*):
        test    rdi, rdi
        je      .L4
        ret
.L4:
        mov     edi, OFFSET FLAT:.LC0
        jmp     puts
main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     rsp, 8
        ret



Changing to this, it does crash


#include <stddef.h>
#include <stdio.h>
#include <string.h>

void
f (const char *str)
{
  size_t len = strlen (str);
  printf("len %zu\n", len);
  if (str == NULL)
    puts ("str is NULL");
}

int
main (void)
{
  f (NULL);
  return 0;
}



I could not see why in your original example it doesn't output as expected as the assembler does show it 'jmp puts' although seems to have optimised and added that code to 'main' as well?

I had expected to see:
$ ./strlen
str is NULL


Cheers, Jonny



[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