Stjepan Groš

C programming tips and tricks

Here I'll collect some useful tips and tricks related to the development of programs written in the programming language C.

Segmentation fault problems

It certainly happened to anyone that did even slightly more complex development in programming language C (or C++) to see infamous Segmentation Fault messages. Something like the following:

$ ./crt cert.pem 
Segmentation fault
$

It's certainly annoying, and also, potential security vulnerability. So, how to find out what exactly happened?

In what follows, I'll suppose that you have access to the source code, otherwise, things are a "bit" more complicated. :D

Method 1

Well, this is the most frequently used method, and equally inefficient, i.e. to put printf function calls throughout the program until you find out the line that causes segmentation fault.

There are at least two problems with this method. The first is obviously that it's labor intensive. Not only you to put all those printf function call, but you have to remove them when you find out what caused segmentation fault. This is annoyance class of shortcoming of this method. The second problem might catch you if you're not careful. Namely, it can happen that the printf function queued output but that wasn't flushed before the segmentation fault occurred. In that case you'll have impression that the segmentation fault occurred before that it actually did.

Method 2

This and the next methods assume the use of debugger (gdb, very powerful debugger, if you know how to use it). But, to use debugger, you first have to compile the program so that it includes debug symbols. That's easy, just add -ggdb option to gcc command line, i.e.

$ gcc -ggdb -o test test.c

Next, load the program into the debugger:

$ gdb ./test

Note that you don't yet specify command line arguments to your program. Then, when you are presented with a gdb's prompt issue the following command:

run <arguments to the program>

And then do anything you usually did, and when the program causes segmentation fault, gdb will stop it and show you exact line where this happened.

This method will be enough, but occasionally you'll have problem that the segmentation fault occurs randomly, or that it occurs somewhere else where you can not run gdb for some reason. For such situations, use the following method.

Method 3

If you run ulimit -a command you'll see the output like this, or some variant of it:

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 40448
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Note the core file size line, it's set to zero. What it basically says is that core files should not be generated. But what are exactly core files. Well, when something abnormal happens to a program the operating system saves complete image of the process into a file to be inspected later. This file is called core and it's named so because the memory of machines used to be called core (it was different type that it is today), so the image of the process in the execution was named core dump.

So the idea is to get this file. To allow core files to be generated, just issue the following command:

ulimit -c unlimited

Then, when the program segfaults, load the program and the core into the debugger:

$ gdb ./test core

And the debugger will tell you where the fault occurred. What's more, you'll be able to inspect all the variables as well as the stack content at the time the segmentation fault occurred.

Few warnings about the core files. It's not that they are disabled without a reason. First, you have to know that those files can be very large and the program during it's lifetime could leave those in different places of the file system. The second thing you have to be aware of is that the core files could contain passwords and other secret information making them security risks.

Usefull links

[20110913] Seventeen steps to safer C code
Unsafe Functions In C And Their Safer Replacements: Strings Part I
comp.lang.c Frequently Asked Questions
C++ FAQ LITE — Frequently Asked Questions
lambdas-in-c

Squeezing binaries

Hello from a libc-free world! (Part 1)
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux
diet libc - a libc optimized for small size