Chapter 5: Finding Memory Errors
The errors that are reported by ZeroFault, whether viewed through
the GUI or the zf_rpt
command, have a specific format to them. They are all identified
by an acronym, and most of them have a memory address that is being
referenced. If the memory is a block that has been allocated then
the allocation traceback is included, and if the block has been
freed then the free traceback is reported as well.
Types of Memory Errors
ZeroFault may report any of the following errors during program execution.
The errors that begin with "Bad" indicate that the memory being referenced
is not allocated to the process, while the errors that begin with
"Uninitialized" indicate that the memory in question has not been
initialized, and is therefore not valid for reading.
BMR: Bad Memory Read
A BMR message is shown when ZeroFault detects a program trying
to read from a memory location not allocated by the program for
use. Some of the causes are:
- Reading beyond the end of a block (this is the most common cause).
- Reading from a location within memory that was allocated and
then later freed.
- Logic errors that cause the program to reference random memory
locations.
Example:
#include <stdlib.h>
main()
{
char *p = malloc(10);
int i;
bzero(p, 10);
for (i = 0 ; i <= 10 ; ++i) // should be "i < 10"
printf("p[%d] = %d\n", i, p[i]); // BMR generated here
}
BMW: Bad Memory Write
This error is reported when a program writes to memory that is
not allocated. Bad memory writes happen when a program tries to
store something in a memory location that should not be altered.
This is a severe error and is very likely to cause catastrophic
results later in program execution.
Example:
#include <stdlib.h>
main()
{
char *src = "hello world\n";
int len = strlen(src);
char *dst = malloc(len);
int i;
for (i = 0; i <= len; ++i)
dst[i] = src[i]; // BMW generated here
}
This generates a BMW when it tries to copy the NUL character from
src to dst, since dst should have been
allocated for strlen(src) + 1 bytes.
UMR: Uninitialized Memory Read
ZeroFault generates this error message when it detects a program
trying to read from a memory location that was not initialized by
the system or the application.
Example:
#include <stdlib.h>
struct foo {
int a;
int b;
};
main()
{
struct foo *p = (struct foo *)malloc(sizeof(struct foo));
printf("p->a = %d\n", p->a); // UMR generated here
}
USTKR: Uninitialized Stack Read
Automatic variables (also known as local or stack variables) do
not have any defined initial state unless they are explicitly initialized.
Reading from an automatic variable before it has been initialized
causes ZeroFault to report an Uninitialized Stack Read Error.
Example:
#include <stdio.h>
main()
{
int rc;
char buf[BUFSIZ];
strcpy(buf, "hello world\n");
rc == fputs(buf, stdout); // Note the "=="
printf("fputs returns %d\n", rc); // USTKR generated here
}
Note: This error is not generated in optimized code.
UFCP: Uninitialized Function Call Parameter
Similar to an Uninitialized Memory Read (UMR), an UFCP is a memory
location which is passed as an argument to a function call, and
has not been initialized before the call to the function is made.
ZeroFault knows the semantics of all the AIX system calls and many
library calls, and it validates the parameters that are passed to
these functions for correct memory usage. See System Calls for more information.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char *foo;
foo = (char *)malloc(10);
bzero(foo, 9); // Should be 10
write(1, foo, 10); // BFCP error generated here
}
BFCP: Bad Function Call Parameter
The BFCP message appears when ZeroFault detects that all of the
memory associated with a function call argument is not allocated
by the program for use. This is similar to a BMR error, but in the context of
a parameter being passed to a function.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char *foo;
foo = (char *)malloc(10);
bzero(foo, 10);
write(1, foo, 20); // BFCP error generated here
}
BFCT: Bad Function Call Target
The target of a function call is the location where the function
call will store information. If that region is not available (either
in address or length) to the program this error is reported. This
is similar to a BMW, but in the context of where
a function call's return value is stored.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char *foo;
foo = (char *)malloc(10);
read(0, foo, 20); // BFCT error generated here
}
The target of the function call is foo. The read
will store 20 bytes of information at foo but foo
is only available for 10 bytes.
BFREE: Bad Free
When a program attempts to tell the system to release a memory
block referenced by an invalid pointer, ZeroFault generates a BFREE
message.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char foo[30];
strcpy(foo, "hello world\n");
printf("%s", foo);
free(foo); // BFREE error generated here
}
DFREE: Duplicate Free
When a program attempts to free a memory block which has already
been freed, ZeroFault generates a DFREE message.
Example:
#include <stdio.h>
main()
{
FILE *f = fopen("tmp","w");
if (f) {
fprintf(f, "hello world\n");
fclose(f);
free(f); // DFREE error generated here, the FILE
// struct was freed by fclose()
}
}
BREALL: Bad Realloc
realloc is a function which changes the size of a block
of memory. When a program requests a realloc for a memory
block which has not been allocated to begin with, ZeroFault generates
a BREALL message.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char inbuf[BUFSIZ], outbuf[BUFSIZ];
char *foo = outbuf; // should be malloc()ed
int foolen = sizeof(outbuf);
foo[0] = '\0';
while (fgets(inbuf, sizeof(inbuf), stdin)) {
if (strlen(inbuf) + strlen(foo) + 1 > foolen)
// BREALL generated on following call
foo = realloc(foo, foolen += BUFSIZ);
strcpy(foo + strlen(foo), inbuf);
}
fputs(foo, stdout);
}
RNULL: Null Pointer Read
When a program attempts to use a pointer which references memory
location zero, ZeroFault generates an RNULL message.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char buf[BUFSIZ];
char *p = fgets(buf, sizeof(buf), stdin);
// if fgets() failed then the next line generates an RNULL
printf("p[0] is %d\n",p[0]);
}
Note: This error is not generated in optimized code.
WNULL: Null Pointer Write
When a program attempts to set a pointer to reference memory location
zero, ZeroFault generates a WNULL message.
Note: A program will always get a segmentation violation immediately
following a WNULL error, since the page pointed to by a NULL pointer
is read-only under AIX.
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
main()
{
char buf[BUFSIZ];
char *p = fgets(buf, sizeof(buf), stdin);
// if fgets() failed then the next line generates a WNULL
p[0] = '\0';
}
WMSG: Warning Message
ZeroFault generates warning messages when the process attempts
to do things that ZeroFault will not allow. The two conditions that
currently generate a WMSG are when the process attempts to close
the file descriptor used by ZeroFault to send information to or
from the user interface and when the process attempts to override
signal handlers installed by ZeroFault to communicate with the user interface
and generate memory leak snapshots.
Some applications attempt to reset all signal handlers or close
all file descriptors at startup or after a fork. These
applications cause WMSG warnings to be generated, but these can
generally be ignored, since there should be no impact on the program.
UNREF_BLOCK: Unreferenced Block
When you generate a memory leak
report, ZeroFault displays a list of unreferenced, or leaked, blocks.
When a program gets a pointer back from a malloc
call, then destroys the pointer without first calling free,
the block of memory once referenced by the destroyed pointer can no longer
be freed or used and thus is known as an unreferenced block.
SEGV: Signal SIGSEGV Received
When the application receives the SEGV signal, ZeroFault generates
this error message and terminates the process. Garbage collection
is not performed.