I am expecting a seg-fault to occurr after the execution of the code below, but it doesn't. Could someone tell me why?
int main(){
float *arr;
cout << arr[0] << "\n" --> This prints out a ZERO. I am expecting a seg-fault.
cout << arr[1000] << "\n" --> This gives me a seg-fault
return 0;
}
I am wondering if this due to the "smart" design of the compiler that alleviates the crash. But I can't be sure.
CodePudding user response:
Since the pointer arr
is not initialized, it probably has the value of whatever value that memory address had when it was previously used.
In your case, the code that used that memory address previously probably used that memory address for storing a pointer, i.e. for storing another memory address that points to a valid object. Even if the lifetime of that object has expired in the mean time, the operating system will probably not be able to detect this, because the memory page was probably not returned to the operating system. Therefore, as far as the operating system is concerned, that memory page is still readable (and possibly also writable) by the program. This probably explains why dereferencing the uninitialized value of arr
does not produce a segmentation fault.
The expression arr[1000]
will attempt to dereference an address that is 4000 bytes apart from the uninitialized value of arr
(assuming sizeof(float)==4
). A typical size of a memory page is 4096 bytes. Therefore, assuming that the uninitialized value of arr
is a memory address that points near the start of a memory page of 4096 bytes, then adding 4000 to that address will not change the memory address sufficiently to make the address point to a different memory page. However, if the uninitialized value of arr
is a memory address that points somewhere in the middle of a memory page, then adding 4000 to that address will make it point to a different memory page (assuming a memory page size of 4096 bytes). This probably explains why your operating system treats both addresses differently, so that one memory access causes a segmentation fault and the other memory access does not fail.
However, this is all speculation (which is made clear by my frequent use of the word "probably"). There could be another reason why your code does not cause a segmentation fault. In any case, when your program invokes undefined behavior (which it does by dereferencing an uninitialized pointer), you cannot rely on any specific behavior. On some platforms, it may cause a segmentation fault, while on other platforms, the program may work perfectly. Even changing the compiler settings (such as the optimization level) may be enough to change the behavior of the program.
I am wondering if this due to the "smart" design of the compiler that alleviates the crash.
The "smart" thing to do in such a case would be to report some kind of error (i.e. to crash), and not to attempt to alleviate the crash. This is because crashing makes the bug easier to find.
The reason why your program is not crashing immediately is that neither your compiler nor your operating system are detecting the error.
If you want such errors to be detected more reliably, then you may want to consider using a feature offered by some compilers that tries to detect such bugs. For example, both gcc and clang support AddressSanitizer. On those two compilers, all you have to do is compile with the -fsanitize=address
command-line option. However, this will cause the compiler to add additional checks, which will significantly decrease performance (by a factor of about two) and increase memory usage. Therefore, this should only be done for debugging purposes.
CodePudding user response:
I am expecting a seg-fault to occurr...
Your program has undefined behavior since the pointer arr
is uninitialized and you're dereferencing it implicitly.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.
For example, here the program doesn't crash but here it crashes.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.