问题
I am trying to get my feet into C, and wrote this program that displays a kb of my RAM in a random location. Here is the code, and it works fine:
#include <stdio.h>
int main(){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
After that, I did the following change in my code, and I get segfaults every time I run my program:
#include <stdio.h>
// Just added this signature
int main(int argc, char *argv[]){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
My spider senses tell me that the segfaults I get are random, and should also be caused in the first example, but running the different programs again and again makes it look like predictable behaviour.
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
回答1:
Both your snippets invoke undefined behavior as you try to
- Go out of bound (
mem++;
, with no allocation) - use uninitialized values (accessing
*mem
)
with the current version.
Remember, pointers do not magically inherit (or acquire) memory, you need to make a pointer point to something valid, in general.
回答2:
The value of mem
is undefined (not initialized), but not random. If before main is called, other C runtime functions, are called, then the slot of stack used by mem
may have a valid pointer within it. Adding parameters to main changes which slot is used and changes behaviour. This can mean the code doesn't crash, although it is not correct.
回答3:
You need to initialize mem
. I guess you're trying to just read random memory, but that isn't allowed. For example, you may be trying to read memory that's used by a different process, or you may be trying to read some address that doesn't even exist in your computer.
By changing the signature for main, you've changed what random junk value is in mem
to start with. The way it probably works is that mem
is taking a random value from some register. When you modified the function signature, argc
and argv
are using those registers instead. Therefor mem
is getting a different junk register value of a junk stack value. In any case, you shouldn't try to follow a junk pointer.
Just because it works in one example, only means you got lucky. You still should not do it. It's very likely it wouldn't work if any little thing was changed.
回答4:
You never initialize mem
, so its contents are undefined. When you attempt to either increment it with ++
or dereference the pointer, you get undefined behavior.
One of the things that can happen with undefined behavior is that a program may appear to work normally, and making a seemingly unrelated change will cause a crash.
来源:https://stackoverflow.com/questions/39154632/why-am-i-getting-segfault-when-changing-the-signature-of-main