Tag Archives: C

How to detect unclosed file handles in C/C++

Sometimes we forget to close file handles which are no longer required in the program. This might eventually eat up some useful resources like open file count, memory, etc. Valgrind does magic at checking a variety of such leakages. All you need is run the program under Valgrind with –track-fds option. Here is the output of a simple C program, executed under Valgrind, which opens a file handle but doesn’t close it.

$ gcc -Wall -g -o fopen fopen.c
$ valgrind --tool=memcheck --leak-check=full --track-fds=yes ./fopen
==2771== Memcheck, a memory error detector
==2771== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==2771== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2771== Command: ./fopen
==2771== 
File opened successfully
==2771== 
==2771== FILE DESCRIPTORS: 4 open at exit.
==2771== Open file descriptor 3: /tmp/fl
==2771==    at 0x4125F73: __open_nocancel (syscall-template.S:82)
==2771==    by 0x40B9ACB: _IO_file_open (fileops.c:233)
==2771==    by 0x40B9C87: _IO_file_fopen@@GLIBC_2.1 (fileops.c:338)
==2771==    by 0x40ADD86: __fopen_internal (iofopen.c:93)
==2771==    by 0x80484F7: main (fopen.c:23)
==2771== 
==2771== Open file descriptor 2: /dev/pts/0
==2771==    
==2771== 
==2771== Open file descriptor 1: /dev/pts/0
==2771==    
==2771== 
==2771== Open file descriptor 0: /dev/pts/0
==2771==    
==2771== 
==2771== 
==2771== HEAP SUMMARY:
==2771==     in use at exit: 352 bytes in 1 blocks
==2771==   total heap usage: 1 allocs, 0 frees, 352 bytes allocated
==2771== 
==2771== LEAK SUMMARY:
==2771==    definitely lost: 0 bytes in 0 blocks
==2771==    indirectly lost: 0 bytes in 0 blocks
==2771==      possibly lost: 0 bytes in 0 blocks
==2771==    still reachable: 352 bytes in 1 blocks
==2771==         suppressed: 0 bytes in 0 blocks
==2771== Reachable blocks (those to which a pointer was found) are not shown.
==2771== To see them, rerun with: --leak-check=full --show-reachable=yes
==2771== 
==2771== For counts of detected and suppressed errors, rerun with: -v
==2771== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

As you can see, at the end Valgrind prints a list of all open file descriptors and stack trace showing where the file was opened.

Compile time assertion

So, what is an assertion? According to gnu.org :

Its a statement in a program that a condition is true at this point in the program. Useful for reasoning about how a program is supposed to behave.

That is – assertions are predicates (or expressions that result in true/false) that programmers add at various places in the code to convey that the specified conditions must be true for the program to continue & execute normally. Assertions can be used to state the precondition – a condition that must hold true before the execution enters a particular code fragment, or postcondition – a condition that must hold true after the execution of a particular code fragment that it follows. These checks would help in early detection of a problem, which might become tricky to detect otherwise.

Assertions mostly work at either compilation time or execution time. While an assertion failure at execution time can abort a running process (in order to avoid a potential catastrophe), the assertion at compile time would cause the build (compilation) itself to fail. Both have their own advantages. Runtime assertions are widely used in C/C++ programs using assert macro. They are checked during the program execution and in case of assertion failure a signal is raised to abort the program. On the other hand compile-time assertions (the subject of this article) work during compilation phase, failure of which results in termination of compilation.

The predicate in compile-time assertion is normally an expression around compile-time constants. They are usually pre-processor macros that inject syntactically invalid code in the program in case of predicate failure & hence the compilation fails.

Lets understand this by taking an example from MySQL code :

In case the expression – expr – evaluates to false, the above macro would create a character array of an invalid size (-1) which would terminate the compilation. Also note that compilation error like ‘redeclaration error’ can be avoided as the array is defined within a do-while loop, opening up the possibility of it being used at multiple places even inside a function or block.

compile_time_assert(sizeof (some_struct) == 12); // sizeof is a compile-time operator.

C11/C++11 standards have added support for compile-time assertions aka ‘static assertions’ by introducing a new keyword static_assert:

static_assert (constant-expression, error-message);
...
  static_assert(sizeof (int) == 8, "A deliberate static assertion..");
..

$ g++ -std=c++0x static_assert.cpp 
static_assert.cpp: In function ‘int main()’:
static_assert.cpp:3:3: error: static assertion failed: "A deliberate static assertion.."

P.S. Here I intentionally omitted an important preprocessor directive #error which can be used to define assertions during preprocessing stage.

Building a MySQL client program on Linux

Building a C program (client) to connect to MySQL server is simple, but at times it can become a little problematic for a newbie to find all the necessary dependencies (includes/libs). The best option that I would recommend is to use the mysql_config script that comes bundled with the MySQL distribution. This shell script when executed with some options, would print all necessary compiler options/flags/switches required to build a MySQL client program. Lets see it in action!

/**
  @file client_version.c
  Display the client version.
*/

#include 
#include                               /* All public MySQL APIs */

int main()
{
    printf("MySQL client version: %s\n", mysql_get_client_info());
    return 0;
}

# mysql_config's output
> .../bin/mysql_config --cflags --libs
-I/path..to../include  -fPIC -g -fabi-version=2 -fno-omit-frame-pointer -fno-strict-aliasing
-L/path..to../lib -lmysqlclient -lpthread -lm -lrt -ldl

# and now pass it down to the compiler..
> gcc client_version.c `/home/nirbhay/project/repo/bld/trunk/bld/bin/mysql_config --cflags --libs`
.. done

> ./a.out 
MySQL client version: 5.7.2-m12

# whoa.. that worked!

Sometimes, the generated binary would complain of missing shared object file. It can be solved by setting up LD_LIBRARY_PATH to the lib directory containing libmysqlclient.so.NN file.

> ./a.out 
./a.out: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object file: No such file or directory
nirbhay@Nirbhay-lenovo:~/project/sandbox/mysql$ ldd a.out 
	linux-vdso.so.1 =>  (0x00007fffce1ee000)
	libmysqlclient.so.18 => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fca652e6000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fca656a3000)

LD_LIBRARY_PATH=/path..to../lib ./a.out
MySQL client version: 5.7.2-m12

Producer/consumer using pthreads

Here I present a C-program to demonstrate the use of pthreads to solve the classical producer/consumer problem. The following (self-explaining) program makes use of pthread’s mutex & condition APIs to achieve synchronization between producer & consumer threads. The program implements a simplified version of the original problem : the producer increments (produces) an integer, a shared resource, while the consumer prints (consumes) it.

Output:

Consumer : "Hello I am consumer #140317330908928. Ready to consume numbers now"
Producer : "Hello I am producer #140317322516224. Ready to produce numbers now"
Producer : 1
Consumer : 1
Producer : 2
Consumer : 2
Producer : 3
Consumer : 3
Producer : 4
Consumer : 4
Producer : 5
Consumer : 5
Producer : 6
Consumer : 6
Producer : 7
Consumer : 7
Producer : 8
Consumer : 8
Producer : 9
Consumer : 9
Producer : 10
Producer done.. !!
Consumer : 10
Consumer done.. !!
Done..

How to debug signal handlers using GDB

At times, one might want to debug a signal handler using GDB. Looks simple, just set a breakpoint at the entry! But there is tiny glitch. Consider the following program.

/*
  @file : sig.c
*/

#include
#include

void signalhandler(int signum) {
  printf("\n SIGINT caught : %d", signum);
}

int main() {
  signal(SIGINT, (void*)signalhandler);

  while (1) {
    printf("\n looping : inside main()");
    sleep(1);
  }
}

Now, lets try to debug the signal handler function using GDB.

# Set a breakpoint in the signal handler function.
(gdb) b signalhandler 
Breakpoint 1 at 0x40058f: file sig.c, line 5.
(gdb) r
Starting program: /home/nirbhay/project/sandbox/c/signal/a.out 

 looping : inside main()
 looping : inside main()
 looping : inside main()
 looping : inside main()
 looping : inside main()
# And now, Ctrl-C
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7af5120 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
82	../sysdeps/unix/syscall-template.S: No such file or directory.
	in ../sysdeps/unix/syscall-template.S
(gdb)

Its apparent that the signal that we are trying to send to the program is being intercepted by GDB and hence control never enters the signal handler (where we have already set a breakpoint).

In such scenarios, GDB’s handle command can be used. With this command we can alter the default behaviour of GDB towards signals. The handle command takes, as argument, a list of signals (to be handled) followed by actions. Of all the actions, ones that are of interest to us are : nostop (do not re-enter debugger if this signal happens) & pass (let program see this signal).

Lets now watch ’em in action :

(gdb) handle SIGINT nostop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y

Signal        Stop	Print	Pass to program	Description
SIGINT        No	Yes	Yes		Interrupt
(gdb) r
Starting program: /home/nirbhay/project/sandbox/c/signal/a.out 

 looping : inside main()
 looping : inside main()
^C
Program received signal SIGINT, Interrupt.

Breakpoint 1, signalhandler (signum=2) at sig.c:5
5	  printf("\n SIGINT caught : %d", signum);
(gdb)

Create static and shared libraries in Unix

Static Library
Lets first look at how static library can be created and used :

(a) Compile print.c to get an object file :
gcc -c print.c -o print.o

(b) Create a static library (archive) of the object file :
ar rcs libprint.a print.o

According to *nix norms, static library’s name should start with ‘lib’ and have ‘.a’ extension. ar is a unix tool to create, modify and extract from archives.

(c) Now compile main.c and link it statically to the library.
gcc -static main.c -L. -lprint -o statically_linked

$ ./statically_linked
hello world!

Shared Library
One of the most important things to note while creating shared libraries is the object files should be compiled with -fPIC option (position-independent code).

(a) gcc -fPIC -c print.c -o print.o

(b) gcc -shared -o libprint.so print.o

(c) gcc main.c -o dynamically_linked -L. -lprint

$ LD_LIBRARY_PATH=. ./dynamically_linked
hello world!

Note: Detailed explanation of the above used gcc switches can be found in gcc manual pages.

gcc : undefined reference error

A very common compiler error when we try to compile a C++ program using gcc on Linux.

$ gcc new.cc 
/tmp/cccP8Jve.o: In function `main':
new.cc:(.text+0xe): undefined reference to `operator new[](unsigned long)'
new.cc:(.text+0x1c): undefined reference to `std::cout'
...

Fix :

(a) Use g++ : g++ new.cc

(b) gcc -lstdc++ new.cc

Simulating disk-full scenario

Unix-like operating systems provide a number of device files in order to simulate different behaviors. In this article we will focus on simulating a “disk-full” scenario using a special file named /dev/full. Its a special file which always returns an error when an attempt is made to write to this file. Lets try to simulate this through a program :

/* disk-full.c */

#include 
#include 
#include 

int main()
{
  int fd;
  ssize_t rc;
  char *buf= "hello world!";

  // Open /dev/full for writing.
  fd= open("/dev/full", "w");

  if (fd == -1)
    printf("Error! Couldn't open the file. %d : %s\n",
           errno, strerror(errno));

  /* Now, lets try to write into this file. */
  rc= write(fd, buf, 1);

  if (rc == -1)
    printf("Error! Couldn't write to the file. %d : %s\n",
           errno, strerror(errno));

  close(fd);
  return 0;
}

Output :

./a.out 
Error! Couldn't write to the file. 28 : No space left on device

Besides /dev/full, there are other interesting device files available under /dev, which can help in a multitude of ways.

> hexdump -Cn80 /dev/urandom 
00000000  ee 32 7c 62 97 17 79 33  71 20 d5 2e 82 32 cd 32  |.2|b..y3q ...2.2|
00000010  26 02 b4 75 4e 90 5d 2f  fb 7f 58 d8 9b ba 50 34  |&..uN.]/..X...P4|
00000020  f5 30 2a e0 b1 95 ea a4  0c 92 ef 57 99 0e b1 ec  |.0*........W....|
00000030  a5 78 df 45 39 df 17 02  12 c1 0b dd cc d0 e0 ad  |.x.E9...........|
00000040  fd 65 c8 71 25 e7 1d 71  c9 77 1d 2a 57 78 be 1f  |.e.q%..q.w.*Wx..|

Using Valgrind with GDB

Valgrind is a very powerful tool for detecting & diagnosing memory related issues in a C/C++ program. Sometimes, the task of locating the actual problematic area becomes increasingly tedious if the code base is huge and complex.

Let us now try to debug a small program running under Valgrind using GDB.

/* leaky.c */
#include
#include

int main()
{
  char *ptr= malloc(100);
  printf("I am a leaky program!\n");
  return 0;
}

Before we move further, one point to note here is that a process running under Valgrind is actually running on a synthetic CPU provided by Valgrind and hence it cannot be debugged directly using GDB [source]. So, in order to overcome this limitation, Valgrind-3.7.0 introduced ‘gdbserver’, an implementation of GDB remote debugging protocol, using which the process can be debugged.

Step 1 : Start the process under Valgrind with –vgdb=yes & –vgdb-error=0 options

> gcc -g leaky.c

> valgrind --vgdb=yes --vgdb-error=0 ./a.out 
==6148== Memcheck, a memory error detector
==6148== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==6148== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==6148== Command: ./a.out
==6148== 
==6148== (action at startup) vgdb me ... 
==6148== 
==6148== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==6148==   /path/to/gdb ./a.out
==6148== and then give GDB the following command
==6148==   target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=6148
==6148== --pid is optional if only one valgrind process is running
==6148==

Step 2 : In a different terminal start GDB

> gdb a.out 
GNU gdb Red Hat Linux (6.5-25.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/libthread_db.so.1".

Step 3 : In the same gdb session,

(gdb) target remote | /usr/lib64/valgrind/../../bin/vgdb
Remote debugging using | /usr/lib64/valgrind/../../bin/vgdb
relaying data between gdb and process 6148
[New thread 6148]
[Switching to thread 6148]
0x0000003f10000a60 in ?? ()
(gdb) b main
Breakpoint 1 at 0x4004e0: file leaky.c, line 7.
(gdb) c
Continuing.

Breakpoint 1, main () at leaky.c:7
7	  char *ptr= malloc(100);
(gdb)

And step through the code further..