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.
Examples of presentations include
"What is the technical term ""undefined behavior"" in the language specification?"
- It's a wrong program or behavior for wrong data.
- The language specification does not specify anything for its behavior.
That's it.
Possible actions are
- The processing system defines its own correct behavior (e.g., Visual C fflush(stdin);
etc.)
- The compiler will diagnose and point out at the time of translation (Example s[-1]
)
- Diagnostics May Result in Compilation Errors
- Diagnostics may result in warnings
- Linker diagnoses and points out at point of link (results above)
-
Diagnoses library functions, OS, etc. at runtime and terminates forcibly due to runtime errors.
- It continues to operate as a program without any diagnosis, but
-
It works as if the programmer were expecting it.
- Unexpected behavior of programmers (Example (2))
- "Running away"
- Other Actions
So
Why are there no errors?
Don't expect to be "detected as an error" in the first place.
First of all: As h2so5 said, I think it's warning.Depending on the compiler options, warning will be an error.
Next, the reason why (2) does not cause warning when compiling is because the compiler happened to understand that s[-1]
was clearly incorrect.
Finally, why doesn't it actually run and get an error? But s[-1]
goes to refer to the "hello" in memory, one before h.Something stored on that memory is retrieved as a result of s[-1]
and printed as a character code in printf
.
"The result says ""Print line feed only"", but there is a high possibility that there is a character code that cannot be displayed on the terminal."(In my environment, DEL code)
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.
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
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.
© 2024 OneMinuteCode. All rights reserved.