Sandeep
Sandeep

Reputation: 19492

Detect segmentation faults at compile time

Can I detect a possible segmentation fault at compile-time?

I understand the circumstance of a segmentation fault. But I am curious if GCC as a compiler has some flags to check for the basic scenarios resulting in segmentation faults.

This would help enormously to take precautions before releasing a library.

Upvotes: 1

Views: 1819

Answers (4)

Ali
Ali

Reputation: 58501

Can I detect a possible segmentation fault at compile-time?

Yes, it is possible. Unfortunately, it is very limited what the compiler can do. Here is a buggy code example and the output from gcc and clang:

#include <stdlib.h>
int main() {
    int a[4];
    int x, y;
    a[5]=1;
    if(x)
        y = 5;
    x = a[y]; 
    int* p = malloc(3*sizeof(int));
    p[5] = 0;
    free(p);
    free(p);
}

For this buggy code, gcc -Wall -Wextra corrupt.c gives

corrupt.c: In function ‘main’:
corrupt.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
corrupt.c:6:7: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

clang catches more:

corrupt.c:5:5: warning: array index 5 is past the end of the array (which contains 4 elements) [-Warray-bounds]
    a[5]=1;
    ^ ~
corrupt.c:3:5: note: array 'a' declared here
    int a[4];
    ^
corrupt.c:6:8: warning: variable 'y' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
    if(x)
       ^
corrupt.c:8:11: note: uninitialized use occurs here
    x = a[y]; 
          ^
corrupt.c:6:5: note: remove the 'if' if its condition is always true
    if(x)
    ^~~~~
corrupt.c:4:13: note: initialize the variable 'y' to silence this warning
    int x, y;
            ^
             = 0
corrupt.c:6:8: warning: variable 'x' is uninitialized when used here [-Wuninitialized]
    if(x)
       ^
corrupt.c:4:10: note: initialize the variable 'x' to silence this warning
    int x, y;
         ^
          = 0
3 warnings generated.

I believe the above code example gives you insight what to expect. (Even though I tried, I could not get the static analyzer in clang to work.)

This would help enormously to take precautions before releasing a library.

As you can see above, it won't be an enormous help, unfortunately. I can only confirm that instrumentation is currently the best way to debug your code. Here is another code example:

#include <stdlib.h>
int main() {
    int* p = malloc(3*sizeof(int));
    p[5] = 0; /* line 4 */
    free(p);
    p[1]=42;  /* line 6 */
    free(p);  /* line 7 */
}

Compiled as clang -O0 -fsanitize=address -g -Weverything memsen.c. (GCC 4.8 also has address santizier but I only have gcc 4.7.2.) The output:

==3476==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000f004 at pc 0x4887a7 bp 0x7fff9544be30 sp 0x7fff9544be28
WRITE of size 4 at 0x60200000f004 thread T0
    #0 0x4887a6 in main /home/ali/tmp/memsen.c:4
[...]

Awesome, we know what went wrong (heap-buffer-overflow) and where (in main /home/ali/tmp/memsen.c:4). Now, I comment out line 4 and get:

==3481==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000eff4 at pc 0x4887d7 bp 0x7fff27a00d50 sp 0x7fff27a00d48
WRITE of size 4 at 0x60200000eff4 thread T0
    #0 0x4887d6 in main /home/ali/tmp/memsen.c:6
[...]

Again, we see what went wrong and where. Finally, I comment out line 6.

==3486==ERROR: AddressSanitizer: attempting double-free on 0x60200000eff0 in thread T0:
    #0 0x46dba1 in free /home/ali/llvm/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:65
    #1 0x48878c in main /home/ali/tmp/memsen.c:7
[...]

Also caught the problem.


If your code has tests, or at least you can run your code with different inputs on your machine before releasing the library, you could probably track down a significant portion of the bugs. Unfortunately, it is not a compile-time solution and you probably don't want to release instrumented code (code compiled with -fsanitize=* flag). So if the user runs your code with an input that triggers a bug, the program will still crash with a segmentation fault.

Upvotes: 0

yakoudbz
yakoudbz

Reputation: 903

gcc -Wall -Werror as mention by Joachim Pileborg are very good ideas. You could also use another compiler maybe. some reports more memory issues. I think you can not do a lot more at compile time.

At running time, I highly recommend Valgrind, which is a amazing tool for detecting memory issues. (don't forget to compile with the -g option)

Upvotes: 0

James Greenhalgh
James Greenhalgh

Reputation: 2491

Can I detect a possible segmentation fault at compile time?

Sometimes, but no, you can't flawlessly detect these scenarios at compile time. Consider the general case in this C code:

volatile extern int mem[];
void foo (int access)
  {
    mem[access];
  }

A compiler would be too noisy if it were to warn about this access at compile time, the code is valid C and a warning is, in general, inappropriate. Static analysis can't do anything with this code unless you have a mechanism for whole-program or link-time analysis.

An additonal optimization flag in GCC 4.8 which can sometimes catch a few out-of-bounds access in loops is `-faggressive-loop-optimizations'. This found a number of issues in the SPEC benchmark suite last year (http://blog.regehr.org/archives/918)

I understand the circumstance of segmentation fault. But i am curious if GCC as a compiler has some flags to check for the basic scenarios resulting in segmention faults.

GCC 4.8 comes with an address sanitizer which can help catch some of these run-time only issues (out of bounds/use-after-free bugs). You can use it with -fsanitize=address.

http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Debugging-Options.html#Debugging-Options

GCC 4.9 (which will be released within the next few months) comes with an undefined behaviour sanitizer and more aggressive optimization of NULL pointer paths, which might help you catch some more issues. When it comes, it will be available with -fsanitize=undefined

http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

Note however that neither of these are "compile-time" solutions, they both rely on instrumenting the binary and performing run-time checks.

Upvotes: 6

Some programmer dude
Some programmer dude

Reputation: 409442

Yes, there are ways of detecting some faults that may cause runtime errors such as segmentation faults. Those ways are called warnings. Many warnings messages are places where you have undefined behavior, and undefined behavior is often the leading cause of runtime crashes.

When I build, I always use the -Wall, -Wextra and -pedantic flags.


Other than that, there are really no good way of detecting all places that may cause segmentation faults (or other runtime errors), except strict coding guidelines, code reviews and plenty of testing.

Upvotes: 0

Related Questions