C: About Array subscripts

Asked 2 years ago, Updated 2 years ago, 30 views

I don't know why the code shown below can be executed.
In (2), I think the subscript is -1, but why is there no error?

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

    int main()
    {
      chars[] = "hello";

      intlen=strlen(s);
      printf("len:%d\n",len);//(1)

      printf("%c\n", s[strlen(s)-1-len]); //(2)
      // printf("%c\n", s[-1]); ->compile error
      // Same as printf("%c\n", s[strlen(s)-6]);->(2)

      return 0;
    }

The printf in the execution result (2) is a new line only print.

len:5

As you can see in the comments, s[-1] only displays a warning, but there was no compilation error.

c

2022-09-29 22:48

5 Answers

The strlen(s)-1-len values are determined only at runtime, so the compiler may not be able to error or warn you.

In the case of Visual C++, although the compiler itself was not warned, static analysis by code analysis

warning C6385: Reading invalid data from 's': the readable size is '6' bytes, but '-1' bytes may be read.

and C6385 warning output.

If you use sizeofs-1 instead of strlen(s) to take advantage of the fact that s is a fixed string instead of a pointer, you should have more types of compilers to warn you of.


2022-09-29 22:48

For gcc only, if you add the following macros and compile them with the -O2 option (optimize level 2), warning will be displayed.

#define strlen(s) (sizeof(s)/sizeof(s[0]))

# Well, it doesn't mean anything, but

$gcc-O2-Wall-o example example.c
example.c:In function 'main':
example.c:12:19:warning:array subscript is above array bound [-Warray-bound]
   printf("%c\n", s[strlen(s)-1-len]); //(2)

By the way, gcc has an optional switch to check the out-of-area access of the array at runtime (-fsanitize=address option).

$gcc --version
gcc(Ubuntu 4.9.2-10ubuntu 13) 4.9.2

$ gcc-O2-g-Wall-fsanitize=address-o example example.c
$ ./example 
len —6
=================================================================
== 18994 == ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffd971e6c1fat pc0x400940bp0x7ffd971e6bf0sp0x7ffd971e6be0
READ of size 1 at 0x7ffd971e6c1f thread T0
    # 0 0x40093f in main example.c:12
    #10x7f5778126a3fin__libc_start_main(/lib/x86_64-linux-gnu/libc.so.6+0x20a3f)
    # 20x4009d8 in_start (example+0x4009d8)

Address 0x7ffd971e6c1f is located in stack of thread T0 at offset 31 in frame
    # 00x40086f in main example.c: 7

  This frame has1 object(s):
    [32,38)'s'<== Memory access at offset 31 underflows this variable
HINT: This may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions*are*supported)
SUMMARY:AddressSanitizer:stack-buffer-underflow example.c:12 main
Shadow bytes around the buggy address:
  0x100032e34d30:00000000000000000000000000000000000000000000000000000000000000000
  0x100032e34d40:0000000000000000000000000000000000000000000000000000000000000
  0x100032e34d50:000000000000000000000000000000000000000000000000000000000000000
  0x100032e34d60:0000000000000000000000000000000000000000000000000000000000000
  0x100032e34d70:000000000000000000000000000000000000000000000000000000000000000
= > 0x100032e34d80: f1 f1 f1 [f1] 06 f4 f4 f4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100032e34d90:0000000000000000000000000000000000000000000000000000000000000000000000000000000000
  0x100032e34da0:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  0x100032e34db0:000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  0x100032e34dc0:000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  0x100032e34dd0:000000000000000000000000000000000000000000000000000000000000000
Shadow byte legend (one shadow byte presents 8 application bytes):
  Addressable:00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone: fa
  Heap right redzone:fb
  Fried heap region: fd
  Stack left redzone: f1
  Stack midredzone: f2
  Stack right redzone: f3
  Stack partial redzone: f4
  Stack after return: f5
  Stack use after scope: f8
  Global redzone: f9
  Global init order: f6
  Poisoned by user —f7
  Continuous container OOB:fc
  ASan internal:fe
==18994 == ABORTING


2022-09-29 22:48

Isn't it because strlen() results are returned at runtime, not at compile time?
If it's optimized, it might be calculated at the time of compilation.


2022-09-29 22:48

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.