Home > Articles

  • Print
  • + Share This
Like this article? We recommend

To better understand the operation and benefits of these memory-testing products, let's step through a few model sessions with one of the products, Parasoft's Insure++. Parasoft offers evaluation licenses for Insure++ on a variety of platforms, including Win2000, WinXP, Linux, and most other UNIXes except MacOS X.

NOTE

This isn't a review of Insure++ or an endorsement of that product; Insure++ just conveniently illustrates the most important functionalities that all the products share.

With Insure++ properly installed, you can start to consider programs such as these:

/*
 * File: badparm1.c
 */
void foo(str)
char *str;
{
 return;
}

main()
{
 int *iptr;

 foo(iptr);
 return (0);
}

This is an example that Parasoft provides in its examples/c distribution directory. Conventionally, you might compile and launch this source with an invocation like this:

gcc -c badparm1.c
gcc -o badparm1 badparm1.o
./badparm1

./badparm1 simply returns immediately. Programmers of the "if it compiles it's shippable" persuasion regard this immediate return as a proof of correctness, but Insure++ knows better. Substituting insure for gcc:

insure -g -c badparm1.c

loads up an error display with a complaint that line 14 has a bad parameter (see Figure 1). Double-clicking the offense pops up the more detailed complaint shown in Figure 2, that the argument passed to foo() is of the wrong type. The complaint is warranted, of course; main() sends an (int *), but foo() expects a (char *).

Figure 1Figure 1 Insure++ and other testing tools make even "silent" programming mistakes visible.

This static syntax analysis should impress you little, of course.

Figure 2Figure 2 Programmers can easily understand most diagnostics that the testing tools report.

Perhaps you realize that if you rewrite badparm1.c slightly:

/*
 * File: badparm1_1.c
 */
void foo(char *str)
{
 return;
}

main()
{
 int *iptr;

 foo(iptr);
 return (0);
}

and compile it:

gcc -c -Wall badparm1_1.c

the standard lint report warns about the same error in these words:

passing arg 1 of ´foo' from incompatible pointer type

Keep in mind, though, that Insure++ is more powerful diagnostically than gcc -Wall because Insure++ doesn't insist that declarations be rewritten to more modern ANSI style.

NOTE

Perhaps you feel about this the same as one colleague, who asked me, "Who uses 30 years old source files these days, without updating them so that modern compilers can accept them?" Lots of us, do, in fact; plenty of the implementation code of the standard utilities for Linux and *BSD still use "this antiquated style," as he calls it. I'm particularly sensitive to this because a lot of Phaseit's consultancy deals with process control and "embedded" computing—think of computers that mix biscuit dough, monitor ship operations, route railroad cars, and so on. I frequently deal with source code that hasn't changed in five, and occasionally fifteen, years. Part of the value Insure++ provides me is that it deals intelligently with the confusing mixes of old C, new C, and C++ that I encounter. This helps me concentrate on deeper issues than coding style and mechanical errors. Later in this series we'll return to examine memory issues as a developer working exclusively in C++ sees them.

Beyond these "legacy" values, Insure++ and other memory checkers are much more than just incremental improvements on lint, though. They also detect a variety of runtime (dynamic) errors. Parasoft's example directory also contains this:

/*
 * File: writover.c
 */
main()
{
  int junk;
  char a[10];

  strcpy(a, "A simple test");
  return (0);
}

Running make writover and selecting the error-report that Insure++ displays provides the detailed explanation in Figure 3. This makes strcpy()'s memory overflow unmistakable.

Figure 3Figure 3 It's far more pleasant to meet memory errors in a display such as this than from a customer complaint about a crash.

This is a powerful result. All the memory-testing products do roughly the same type of evaluation—not just for "toy" example programs, but in large, complex applications. They detect bounds violations, memory leaks, uninitialized variables, and several more obscure errors. They're easy to use, generate sensible reports and displays, and always—always—find faults that otherwise would have turned up only during live use by customers.

  • + Share This
  • 🔖 Save To Your Account