[Table of Contents] [Next] [Previous]

Chapter 16

Stack and Global Data Error Detection


This chapter discusses Memory Advisor's ability to find and report errors in accessing memory that is either on the stack or is global data.

Note: This chapter applies to OMT mode only.

Memory Advisor Error Messages
Stack Errors
Global Data Errors
Unsafe Data Areas
Maximizing Data Error Detection on SunOS and Solaris

Memory Advisor Error Messages


In reporting both stack and global data errors, Memory Advisor often reports the address of the error as the name of a variable plus an offset from that variable. For example, it reports an uninitialized read of the following code at buf + 0x2 (or something similar, depending on your compiler):

foo()
{
	char buf[10];

	if( buf[2] == 'a' )						/* uninitialized read */
	...

Memory Advisor provides a similar message if you are reading from a member of a structure. It gives the offset of the member from the beginning of the structure.

Also, if you are accessing a memory location that does not have a label (a compiler-private return area on the stack, for example), Memory Advisor reports the error as an offset from the last variable with a label.


Stack Errors


Memory Advisor detects the following errors for data declared on the stack:

Following is an example of a program that overwrites the stack frame, which Memory Advisor detects:

foo()
{
	int buf[16];
	int i;

	i = 0;
	while(1)
		buf[i++] = 0;
}

The value of i where Memory Advisor will detect the error depends on where the array buf is in relation to the boundary region that separates stack frames. Memory Advisor will detect the error once you attempt to access the memory in the boundary areas between stack frames, and it could detect the error as soon as you attempt to access buf[16] in the example.

Memory Advisor can always detect the use of uninitialized memory that corresponds to stack variables. For example:

int bar(int count)
{
	int i;

	/* Memory Advisor will report an error here because i is 
	   uninitialized. */
	return count + i;
}

Memory Advisor will parse the debugging information (if present) in the object files and shared libraries to determine which function return data types correspond to a pointer.

For functions known to return pointers, Memory Advisor can detect errors where the function attempts to return pointers into its own stack frame. For example:

char * wax()
{
	char buf[10];

	strcpy(buf, "test");

	return &buf[0];    /* Memory Advisor will report an error here */
}

In this example, the function is returning a pointer to one of its own stack variables. Once the function returns, the stack frame no longer exists, and you can reuse it when you call another function. In addition, a signal handler can reuse it when a signal arrives.

Note that Memory Advisor can only detect this class of error in object files compiled with debugging.

Memory Advisor does not detect the following errors for data declared on the stack:

Memory Advisor cannot detect small data overwrites or underwrites on the stack, because such references appear valid at the object code level.

The following code fragment illustrates an overwrite:

char		buf1[5];
char		buf2[5];

buf1[6] = 'a';

At the object code level, there is no difference in the address of buf1[6] and buf2[1], even though at the C level, the reference to buf1[6] is semantically incorrect. Memory Advisor cannot complain about the statement buf1[6] = 'a'; because it refers to a perfectly valid and writable address. (Note: This situation does not occur for every compiler and operating system.)

If you suspect that you have this sort of data corruption, often the easiest solution is to install a Memory Advisor watchpoint at the location you believe is being corrupted. To do this, use the MaWatchAdd() function:

MaWatchAdd(&buf2, 4, "write");
See Chapter 5, Watchpoints, for more information.

Memory Advisor cannot detect addresses that are so far out of the current stack frame that they appear to be valid references into another stack frame. Memory Advisor marks a small boundary area on either side of every stack frame as out of bounds. If your program attempts to cross these boundaries, Memory Advisor will complain. If, however, you reference data through a pointer whose value is within a valid stack frame, Memory Advisor will not complain. You cannot change the size of the stack boundary area.

Again, if you suspect this kind of data corruption, set a watchpoint at the address being corrupted.


Global Data Errors


Memory Advisor detects the following errors for global data:

Although global data areas always start out initialized to zero, Memory Advisor may still report reads of uninitialized data from such areas if you have copied uninitialized data into these areas. By default, Memory Advisor does not warn about copying uninitialized data, so it is possible to copy uninitialized areas into global data without Memory Advisor complaining. If you set the MA_WARN_COPY_UNINIT option to on, Memory Advisor will warn about copying uninitialized data.

Memory Advisor detects overwrites of global data. For example:

char name[16];

void init_var()
{
	int i;

	for(i=0; i<=16; i++)
		name[i] = 0;
}

This example attempts to write to name[16], even though this is outside the region of memory that the program has allocated for that variable. In this case, Memory Advisor will detect the overwrite and give you a detailed message describing the error.

Memory Advisor can detect errors involving overwrites of global data by inserting boundary regions between the global variables and prohibiting access to memory in the boundary regions. The default boundary size is 8 bytes, so it is possible to access memory far enough beyond one global variable that you have completely bypassed the data boundary and are instead accessing memory in the address space assigned to another global variable. The following example illustrates this:

int buf[5];
int buf1[5];

void init_buf()
{
	buf1[15] = 7;
}

Using the default data boundary size of 8, Memory Advisor would not detect the reference to buf1[15] as out of bounds, because it skips the boundary area entirely. Any reference to buf[6] through buf[13] would result in an error, however. (Note: This situation does not occur for every compiler and operating system.)

You have two options if you suspect this is a problem in your program:


Unsafe Data Areas


Compilers generate certain references to data that are extremely difficult to interpret at the object code level. These references are called section-based relocations. If Memory Advisor interprets these data references incorrectly, your program's behavior will be unpredictable. Consequently, when Memory Advisor encounters section-based relocations in your program, it will not insert data boundaries.

The problem with section-based relocations is analogous to the example above of contiguous data areas on the stack, in which it is not possible to determine whether a given address corresponds to buf1[6] or buf2[1]. With section-based relocations, it is not possible to determine whether a data reference is to one data area or another. If Memory Advisor inserts data boundaries between data areas, it must update all data references accordingly. It cannot do this if it cannot interpret what these references mean.

To determine if Memory Advisor is not inserting data boundaries into a particular object file, you can run the memadvise command with the -v2 command-line option. As Memory Advisor processes the object file, it will indicate whether it found any section-based relocations. If Memory Advisor does not process the file because it is up to date, you can force Memory Advisor to process it with the -f command-line option.

At your own risk, you can force Memory Advisor to insert data boundaries in object files with section-based relocations by using the -du command-line option, although we strongly discourage this.


Maximizing Data Error Detection on SunOS and Solaris


To maximize Memory Advisor's usefulness in detecting data errors on SunOS and Solaris, we recommend that you do the following:

In no case do you need to modify your source code to work with Memory Advisor. These strategies are for those people who need or want to maximize the data error detection for specific programs.


Copyright ©1996 PLATINUM technology, inc. All rights reserved.
Last modified 1/29/96
For more information contact info@platinum.com