Friday, January 21, 2011

How to add Purify to automake project

This post describes how to add Purify support to the Automake project.

In order to instrument your automake project with Purify, you would need to perform following modifications to your project files:
  • add SUPPORT_PURIFY m4 macro to the project files
  • modify configure.ac
  • modify $rootdir/Makefile.am
  • add Purify-specific bootstrap script

Add m4 macro to test Purify installation


Under $rootdir create macros directory and add support_purify.m4 file:

AC_DEFUN([SUPPORT_PURIFY],
[
dnl Name: support-purify.m4
dnl
dnl Description: Definition of SUPPORT_PURIFY m4 macro.
dnl
dnl

AC_ARG_ENABLE(purify-linker,
[AC_HELP_STRING([--enable-purify-linker],
[Augment the linker with purify.])],
[enable_purify_linker=$withval],
[enable_purify_linker=no])

if test "x$enable_purify_linker" = xyes ; then
  echo "Option enabled --enable-purify-linker=yes"
  AC_DEFINE([USE_PURIFY_LINKER],[],[Link-time support for Purify.])
  use_purify_linker=yes
else
  use_purify_linker=no
fi

dnl ====================================================
dnl Specify location of PURIFY

AC_MSG_CHECKING(for purify)

AC_ARG_WITH(purify,
[ --with-purify=PATH Specify the prefix where purify is installed],
,
test "$purify_PREFIX" && with_purify="$purify_PREFIX")

test "$with_purify" &&
test ! "$with_purify" = no &&
purify_PREFIX="$with_purify"

AC_MSG_RESULT($purify_PREFIX)
AC_SUBST(purify_BIN)

echo "purify_BIN is $purify_BIN"

dnl ====================================================
dnl Specify options for Purify

AC_ARG_WITH(purify-options,
[ --with-purify-options=ARG manually set PURIFY options to ARG],
PURIFY_OPTIONS=$with_purify_options,
PURIFY_OPTIONS="-follow-child-processes=yes -windows=no -cache-dir=${HOME}/tmp -always-use-cache-dir=yes -view-file=${HOME}/tmp/%v-%p.pv -messages=batch")

AC_SUBST(PURIFY_OPTIONS)

dnl ====================================================
dnl Augment linker

if test "x$enable_purify_linker" = xyes ; then
echo "augment the linker"
AUX_LINKER="${purify_BIN} ${PURIFY_OPTIONS}"
echo "AUX_LINKER = $AUX_LINKER"
fi

AC_SUBST(AUX_LINKER)

CCLD="$AUX_LINKER $CXX"
CXXLD="$AUX_LINKER $CXX"

AC_SUBST(CXXLD)
AC_SUBST(CCCLD)

echo "In macro SUPPORT PURIFY: CXX = $CXX"
echo "In macro SUPPORT PURIFY: CXXLD = $CXXLD"
dnl ====================================================
dnl End of Purify macro definition
]
)

Modify configure.ac


m4_include([macros/support_purify.m4])
SUPPORT_PURIFY

Modify $topdir/Makefile.am


Add 'bootstrap-dev-purify' and 'macros/support_purify.m4' to your EXTRA_DIST target.

Purify-specific bootstrap script


Modify your bootstrap script to enable Purify instrumentation:
autogen.sh
configure --prefix=$INSTALLDIR --enable-purify-linker=yes
make

Conclusion


Now you can run 'bootstrap-dev-purify' script to let automake test Purify on your system and if successful, instrument your project with Purify-enabled object code.

Tuesday, January 11, 2011

Safe sprintf() C++ style

Scanning the legacy "C" code, often I find code snippets similar to the following code:

#include <stdio.h>

static const char msg_buf [1024];

static void log (const char* msg) {  /* log the message */ }
/* ... some place later */

int i = 43;
const char* msg = "Safety first"

sprintf (msg_buf, "%s : %d\n", msg, i);
log (msg_buf);

Any static code analysis tool such as (cppcheck, flawfinder, RATS, etc.) will mark call to sprintf() as unsafe on the ground that it doesn't check for buffer overflow.

However, if you can compile your program with C++ compiler, the easiest fix to such a problem would be to use ostringstream C++ standard library string buffer instead:

#include <sstream>

static void log (const char* msg) 
{  
   /* log the message */ 
}

/* Add a wrapper version of log() function
* that accepts stream string as an argument
* and clears up buffer after the message
* has been logged.
*/ 
static void log (const std::ostringstream& msg)
{
    log (msg.str().c_str());
    msg.str (""); 
}

namespace {
    std::ostringstream msg_buf;
}

/* ... some place later */

int i = 43;
const char* msg = "Safety first."

msg_buf << msg << " " << i << std::endl;

log (msg_buf);  /* overloaded */ 


Note that we added a wrapper log() function to help us hide the syntax and to clean up the buffer after the message has been logged.

Formatting Options

It takes time to get used to C++ stream formatting.
For example, the following code snippet prints an integer number as upper case hex to the buffer:

#include <stdio.h>

int i = 43; 
char msg_buf[1024];

snprintf (msg_buf, 1024, "Print hex number : %0X.", i);

To achieve equivalent result with C++ stream, you need to insert a number of stream manipulators first.

std::hex manipulator specifies that integers should be treated as hexadecimal (base 16) values.

std::showbase manipulator specifies that the base of a number is to be output ahead of the number (a leading 0 for octals; a leading 0x or 0X for hexadecimals). This setting is reset with stream manipulator noshowbase.

std::setfill (char) manipulator pads empty space of the justified field with char character. By default, the filler is a whitespace.

std::uppercase manipulator converts the stream to upper case.

std::width (d) manipulator specifies the minimum widht of the data field.

#include <sstream>
#include <iomanip>

int i = 43;
std::ostringstream msg_buf;

msg_buf << "Hex number : "
        << std::hex << std::showbase 
        << std::setfill('0') << std::uppercase
        << i << ".";


For example, to print a date in YYYYDDMM format, the "C" code might look like this:

#include <stdio.h>

int year  = 2011;
int day   = 14;
int month = 1;
char msg_buf[1024];

snprintf (msg_buf, 1024,
          "Today's date: %04d%02d%02d", 
          year, day, month);

We can easily rework the solution in a safe C++ manner:

#include <sstream>
#include <iomanip>

int year  = 2011;
int day   = 14;
int month = 1;

std::ostringstream msg_buf;

msg_buf << std::setw(4)
        << year
        << std::setw(2) << std::setfill('0') 
        << day
        << std::setw(2) << std::setfill('0') 
        << month;

Tuesday, January 4, 2011

Qt4 SDK packages Fedora Core 14

I took me some cycles to figure out which RPM packages to install under Fedora Core 14 running GNOME desktop to begin development with Qt4 libraries.

Here is the bare minimum:
  • qt-4.7.1-7.fc14.i686
  • qt-x11-4.7.1-7.fc14.i686
  • qt-devel-4.7.1-7.fc14.i686
And documentation, examples, etc:
  • qt-doc-4.7.1-7.fc14.noarch
  • qt-demos-4.7.1-7.fc14.i686
  • qt-examples-4.7.1-7.fc14.i686
To develop with Qt4 IDE:
  • qt-creator-2.1.0-4.rc1.fc14.i686 

To develop with WebKit:
  • qt-webkit-4.7.1-7.fc14.i686
  • qt-webkit-devel-4.7.1-7.fc14.i686
To develop for smart phones, netbooks, and non-mobile personal computers:
  • qt-mobility-1.0.1-3.fc14.i686
  • qt-mobility-devel-1.0.1-3.fc14.i686
  • qt-mobility-doc-1.0.1-3.fc14.noarch