This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why don’t I get a segmentation fault when I write beyond the end of an array?
This code compiles and runs without any error. But how?
#include <stdio.h>
int main (void)
{
int foo[2];
foo[8] = 4; /* How could this happen? */
printf("%d\n", foo[8]);
return 0;
}
I'm compiling with GCC 4.7.2 on Arch Linux x86_64.
gcc -Wall -o "main" "main.c"
Because undefined behavior doesn't mean "you will receive a segfault", that would be defined behavior.
Let's assume you're running in debug mode and your compiler is padding your stack/local variable space. You're probably just writing into some unused part of the stack space.
Build a release version on a Monday when your compiler is feeling cranky and now you overwrite the return address, or the code that sets up the call to printf, whatever. Oops.
Just one possible outcome, but you get the idea.
foo[8] may be allocated for your program (padding purpose, for instance), belong to your operating system. With an undefined behavior, anything can happen; you are unlucky, because it works.
Try
foo[1000000]=42;
and see what happens.
Related
Consider this demo programme:
#include <string.h>
#include <unistd.h>
typedef struct {
int a;
int b;
int c;
} mystruct;
int main() {
int TOO_BIG = getpagesize();
int SIZE = sizeof(mystruct);
mystruct foo = {
123, 323, 232
};
mystruct bar;
memset(&bar, 0, SIZE);
memcpy(&bar, &foo, TOO_BIG);
}
I compile this two ways:
gcc -O2 -o buffer -Wall buffer.c
gcc -g -o buffer_debug -Wall buffer.c
i.e. the first time with optimizations enabled, the second time with debug flags and no optimization.
The first thing to notice is that there are no warnings when compiling, despite getpagesize returning a value that will cause buffer overflow with memcpy.
Secondly, running the first programme produces:
*** buffer overflow detected ***: terminated
Aborted (core dumped)
whereas the second produces
*** stack smashing detected ***: terminated
Aborted (core dumped)
or, and you'll have to believe me here since I can't reproduce this with the demo programme, sometimes no warning at all. The programme doesn't even interrupt, it runs as normal. This was a behaviour I encountered with some more complex code, which made it difficult to debug until I realised that there was a buffer overflow happening.
My question is: why are there two different behaviours with different build flags? And why does this sometimes execute with no errors when built as a debug build, but always errors when built with optimizations?
..I can't reproduce this with the demo program, sometimes no warning at all...
The undefined behavior directives are very broad, there is no requirement for the compiler to issue any warnings for a program that exhibits this behavior:
why are there two different behaviours with different build flags? And why does this sometimes execute with no errors when built as a debug build, but always errors when built with optimizations?
Compiler optimizations tend to optimize away unused variables, if I compile your code with optimizations enabled I don't get a segmentation fault, looking at the assembly (link above), you'll notice that the problematic variables are optimized away, and memcpy doesn't get called, so there is no reason for it to not compile successfuly, the program exits with success code 0, whereas if don't optimize it, the undefined behavior manifests itself, and the program exits with code 139, classic segmentation fault exit code.
As you can see these results are different from yours and that is one of the features of undefined behavior, different compilers, systems or even compiler versions can behave in a completely different way.
Accessing memory behind what's been allocated is undefined behavior, which means the compiler is allowed to do anything. When there are no optimizations, the compiler may try to guess and do something reasonable. When optimizations are turned on, the compiler may take advantage of the fact that any behavior is allowed to do something that runs faster.
The first thing to notice is that there are no warnings when compiling, despite getpagesize returning a value that will cause buffer overflow with memcpy.
That is the programmer's responsibility to fix, not the compiler. You'll be very lucky if a compiler manages to find potential buffer overflows for you. Its job is to check that your code is valid C then translate it to machine code.
If you want a tool that catches bugs, they are called static analysers and that's a different type of program. At some extent, static analysis might be integrated in a compiler as a feature. There is one for clang, but most static analysers are commercial tools and not open source.
Secondly, running the first programme produces: ... whereas the second produces
Undefined behavior simply means there is no defined behavior. What is undefined behavior and how does it work?. Meaning there's not likely anything to learn from examining the results, no interesting mystery to solve. In one case it apparently accessed forbidden memory, in the other case it mangled a poor little "stack canary". The difference will be related to different memory layouts. Who cares - bugs are bugs. Focus on why the bug happened (you already know!), instead of trying to make sense of the undefined results.
Now when I run your code with optimizations actually enabled for real (gcc -O2 on an x86 Linux), the compiler gives me
main:
subq $8, %rsp
call getpagesize
xorl %eax, %eax
addq $8, %rsp
ret
With optimizations actually enabled, it didn't even bother calling memcpy & friends because there are no side effects and the variables aren't used, so they can be safely removed from the executable.
This question already has answers here:
How printf("%d","<string>") work in C?
(2 answers)
Closed 4 years ago.
printf("%d", "10+10");
then I get "17661648" and similar thing in too
printf("%d", "Hello");
What is this value?
sum of "1,0,+,1,0" "H,e,l,l,o" as ASCII code in decimal number? or just a garbage value?
According the the C11 standard n1570 (see its §7.21.6.1) you've got undefined behavior (UB), which is also documented here or in printf(3). So be very scared, since arbitrarily bad things could happen. So take the habit of reading the documentation of every function that you are using.
If you ask your compiler to disassemble the generated form of your program (e.g. by compiling with gcc -S -O -fverbose-asm if you use GCC, on Linux/x86-64) you'll discover that the address of the string literal "10+10" is passed (on 64 bits) and then truncated (inside printf, because of the %d) to an int. So the 17661648 could correspond to the lowest 32 bits of that address.
Details are of course implementation specific (and could vary from one run to the next one because of ASLR, depends upon the compiler and the ABI and the target system). To actually understand and explain the behavior requires diving into many details (your particular computer, your particular compiler and optimization flags, your particular operating system, the compiler generated assembler & machine code, your particular C standard library, etc....) and you don't want to do that (because it could take years).
You should take several hours to read more about UB. It is an essential notion to understand when programming in C, and you should avoid it.
Any good compiler would have warned you, and then you should improve your code to get no warnings. If using GCC, be sure to compile with gcc -Wall -Wextra -g to get all warnings and debug info. Then use the gdb debugger to understand the actual behavior of your program on your system. In all cases, be sure to configure your C compiler to enable all warnings and debug info, and learn to use your debugger. Read How To Debug Small Programs.
Someting like this should work:
printf("Hello");
total = 20;
printf("10+10 = %d", total);
I encountered my first Segmentation Fault today (newbie programmer). After reading up on what a segmentation fault is (Thanks for all of the helpful info on this site, as well as Wikipedia's lengthy explanation), I'm trying to determine the easiest way to go about finding where my fault is occuring. It's written in C and the error is occuring on a *NIX based system (I'm not sure which one to be honest... 99% sure it's Linux). I can't exactly post my code as I have numerous files that I'm compiling that are all quite lengthy. I was just hoping for some best practices you have all observed. Thanks for your help.
P.s. I'm thinking the error is coming from dereferencing a NULL pointer or using an uninitialized pointer. However, I could definitely be wrong.
Use a debugger, such as gdb or if this is not applicable a strace tool to get a better insight into where the segfault occurs.
If you use gcc, make sure you compile with -g switch to include debugging information. Then, gdb will show you the exact location in a source code where it segfaults.
For example, if we have this obvious segfaulty program:
new.c
#include <stdio.h>
int main()
{
int *i = 0x478734;
printf("%d", *i);
}
We compile it with gcc -g new.c -o new and then run the gdb session with gdb new:
We issue the run command in the interactive session and the else is clear:
(gdb) run
Starting program: /home/Tibor/so/new
[New Thread 9596.0x16a0]
[New Thread 9596.0x1de4]
Program received signal SIGSEGV, Segmentation fault.
0x0040118a in main () at new.c:6
6 printf("%d", *i);
(gdb)
As DasMoeh and netcoder have pointed out, when segfault has occured, you can use the backtrace command in the interactive session to print a call stack. This can aid in further pinpointing the location of a segfault.
The easiest way is to use valgrind. It will pinpoint to the location where the invalid access occours (and other problems which didn't cause crash but were still invalid). Of course the real problem could be somewhere else in the code (eg: invalid pointer), so the next step is to check the source, and if still confused, use a debugger.
+1 for Tibors answer.
On larger programs or if you use additional libraries it may also be useful look at the backtrace with gdb: ftp://ftp.gnu.org/pub/old-gnu/Manuals/gdb/html_node/gdb_42.html
I reopen this posts for people passing here since I've just corrected a segfault I've made using gcc.
You should consider using the flag -fsanitize=address which can sometimes highlight your segfault with high precision.
I have a C program with a multi-line macro and the program crashes within the macro, how can I pinpoint the location within the macro where the crash happens?
Here is a simplified version of my program. In reality CRASHES is multiple lines long and not easily expandable manually.
#include <stdio.h>
#include <stdarg.h>
#define CRASHES(ptr) \
(*(ptr) == 123)
main()
{
char *foo = NULL;
if (CRASHES(foo))
printf("This will never happen.");
}
When compiling and running this with gdb a.out I get the expected EXC_BAD_ACCESS (I am on Mac OS X with gdb 6.3), however the crash points to line 8 and not line 4 where the crash is actually caused.
I already tried compiling the program with additional debugging flags -gdwarf-2 and -g3 as suggested by the docs and inserted several assert()s within the macro itself. Unfortunately that did not provide more information.
lots of valuable information here about macro debugging.
...another approach is to use the preprocessor, i.e. compile it using -E and copy-paste the expanded macro into your src-code and see if you can debug from there.
Of course this crashes since you are deferencing a NULL pointer...(it was not this the question right?). With this particular example, it is easy: gcc -g2, and gdb says
Program received signal SIGSEGV, Segmentation fault.
0x080483d9 in main () at crash.c:10
10 if (CRASHES(foo))
which is rather clear, you expand by yourself the macro and see why (since *foo == 123 access memory you can't read, since foo is NULL). In more complex cases, gcc -E helps, or avoid using macros.
You don't say anything about how it crashes. If it's a segfault, be aware that it might occur a bit later than when you actually dereferenced the bad pointer value.
I there any way you could convert it to an actual function? This is one of the great evils of macros.
I have a long program in c over Linux, that gives me segmentation fault after main returns.
Its a long program, so I cant post it. So can you help me what can make such error?
Thank You.
Wow, Those answers came really fast. Thank you all.
I think i worked it out, i forgot to malloc a string and used it as buffer.
Now that I've malloced it, it does not signal me with a segmentation fault.
Once again, thank you all.
Guess: you might be accidentally corrupting the stack in main so it's lost the return address. Do you have a string buffer there that you could be overrunning?
If not, you should try:
running the program under valgrind
debugging the program with gdb to catch the crash and see where you are at that point; you can also debug the core file dumped
It might help to install glibc-debug packages if your distro has them since you'll be in glibc code at that point.
Use GDB and print stack trace on SIGSEGV signal. Then at least post that here so we can be a little bit more helpful.
Provided you compiled with:
$ gcc -g prog.c -o prog
Then run it under GDB:
$ gdb ./prog
gdb> r
When you get SIGSEGV signal (Segmentation Fault), do this:
gdb> bt
Then see what's on the stack trace to see what is causing the segmentation fault.
If the segmentation fault arises after main() returns, it usually means that a global defined thing went wrong. It is hard to help you with so little info. Send us more info !
my2c
If it's after main() returns, then according to the Standard all destructors have been run (although I wouldn't put it past an implementation to fudge this some), unless the function atexit() has been used. That function registers a function that will be called after main() returns, effectively (if I'm reading 3.6.3 aright). You might check to see if there is an atexit in your program somewhere, if only for completeness.
Depending on what you mean by "after main returns", you may be running destructors for static objects when the program crashes. Check those. (Also, post what you observed that made you think it was after main() returned. You could be wrong there.)
If not, then you've invoked undefined behavior somewhere, very likely in corrupting the stack somehow. See Rup's answer for suggestions there.