Skip to content

c programming

clang compiler

This is supposedly a faster compiler, but i cannot detect that. For a test run on the backend (debug + release + test + profile) gcc took 14 second and clang took 18 seconds.

However some tools like libFuzz and maybe more work better wit clang/llvm so at least know how to use it.

For now here is the errorformat for clang because that took annoyingly long to find. One for errors and one for warnings.

errorformat
setlocal errorformat+=%f: line %l\, col %c\, %trror - %m
setlocal errorformat+=%f: line %l\, col %c\, %tarning - %m

valgrind new version

Options like --db-attach are gone !! To stop inside the debugger at first error you need to use the option:

valgrind
valgrind --leak-check=yes --vgdb-error=0 <program>

Then you will be told what to do, basically start gdb separately and attach. Then start the program in gdb !

start from gdb
1
2
3
gdb <program>
target remote | /usr/local/lib/valgrind/../../bin/vgdb
run

More difficult, but it works.

suppressions

To keep the number of suppressions down a bit. You will notice when letting valgrind print suppressions they all look alike, but slightly different and so they won't match. there are some details here : https://wiki.wxwidgets.org/Valgrind_Suppression_File_Howto

But a working example for libglib is these short entries to be found in klopt.supp in the backend sources :

suppressions
{
   libglib all Conditional checks
   Memcheck:Cond
   obj:/lib/x86_64-linux-gnu/ld-2.28.so
}   

{
   libglib Leak checks
   Memcheck:Leak
   obj:/lib/x86_64-linux-gnu/ld-2.28.so
}

{   
   libglib Leak checks, for all alloc functions
   Memcheck:Leak
   fun:*alloc
   ...
   obj:/lib/x86_64-linux-gnu/ld-2.28.so
   ...
}   

So you provide a name, then the type of Mem check which cannot be wildcarded. And then the ld file that is causing the problems, according to the documentation you CAN use wildcards in that filename.

The third one still seemed to be necessary, the ... ellipses in this section are stack wildcards, and so mean any stack trace that contains that ld file, and also all functions that have alloc in their name.

unused functions and warnings

Sometimes you just want a function to be temporarily unused without the compiler bitching about it. Here is a way of fixing that:

unused functions
1
2
3
__attribute__((unused)) static void notyetused_func(void) {
    print("I will be used again !!\n");
}

stacktrace dump

You can't always run from the debugger, for one it is slower with debugging info, and another you might want the program to be restarted and not hang in the debugger waiting for you attention.

stacktrace() from execinfo.h

One solution for this is the backtrace() function, which you could use :

backtrace
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>


void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

void baz() {
 int *foo = (int*)-1; // make a bad pointer
  printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler
  foo(); // this will call foo, bar, and baz.  baz segfaults.
}

This is a complete program, it will crash and than print :

output
1
2
3
4
5
6
7
8
9
Error: signal 11:
./a.out[0x4006f8]
/lib/x86_64-linux-gnu/libc.so.6(+0x321e0)[0x7f64e8cc81e0]
./a.out[0x400751]
./a.out[0x400774]
./a.out[0x400784]
./a.out[0x4007ae]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7f64e8cb4ead]
./a.out[0x4005f9]

Not very descriptive i hear you say, so try compiling it with -rdynamic :

-rdynamic
gcc -g -rdynamic test.c

You will get another stacktrace :

output
1
2
3
4
5
6
7
8
9
Error: signal 11:
./a.out(handler+0x1c)[0x400a98]
/lib/x86_64-linux-gnu/libc.so.6(+0x321e0)[0x7f52aa2f01e0]
./a.out(baz+0x14)[0x400af1]
./a.out(bar+0xe)[0x400b14]
./a.out(foo+0xe)[0x400b24]
./a.out(main+0x28)[0x400b4e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7f52aa2dcead]
./a.out[0x400999]

It will give you the functions names on the stack, but also an address which you can translate with :

addr2line
addr2line ./a.out 0x400af1

For this the -g option is needed, or it won't show you anything, but otherwise :

output
??:0
/home/kees/projects/klopt/grid/src/baz.c:23

Very handy. Of course you need to get down the stack a little because the top entry gives :

top entry
/home/kees/projects/klopt/grid/src/baz.c:13

So.. the handler itself, and the second one is from libc so probably the signal handling function. It is pretty clear you need the third line anyway.

catchsegv

To be done, .... since it used to start the program, you could also use gdb directly, though this does give you the chance to restart again.