Kenton Lee

Avoiding Motif Memory Leaks

by Kenton Lee

March, 1996

Copyright © 1996 Kenton Lee, All Rights Reserved.


This is the second of two Advanced Application Development columns focusing on problems that X Window System application programmers frequently have with dynamic memory. Dynamic memory problems are among the most important and complex problem areas faced by C and C++ programmers.

Last month, I presented an X-oriented tutorial on understanding, avoiding, and debugging dynamic memory errors.[Lee2-96] This month, I'll focus on a specific, important dynamic memory issue: memory leaks involving the Motif library.

Motif Memory Leak Overview

Like most object-oriented frameworks, Motif frequently allocates dynamic memory. Sometimes Motif frees the memory itself, but other times it expects the application program to explicitly free the memory. Unfortunately, the official Motif documentation[OSF] isn't always clear about the application program's responsibilities. The unofficial tutorials are generally even less complete and less accurate.

I've been studying the Motif source code and will try to fill in the documentation holes with this column. This material is based on Motif version 1.2.4, which is probably the most commonly used version right now. Most of the material will also apply to other versions of Motif. (Of course, some of the Motif 1.2 interfaces did not exist in earlier version of Motif.)

I'm not covering the other X libraries in this column. Fortunately, the Xlib and X Toolkit (Xt) documentation[Scheifler][McCormack] is much more complete and accurate about when and how the application program must free dynamic memory.

The remainder of this column discuss places where Motif allocated dynamic memory and if and how the application program must free it. First, I'll cover dynamic memory that is associated with specific Motif widgets (resources and convenience functions). Later, I'll cover non-widget Motif convenience functions. I hope it helps you improve the quality of your code.

Motif Widget Resources and Dynamic Memory

As I've discussed in previous columns, the primary programming interfaces to Motif widget are its resources.[Lee6-95] Most widget functionality can be controlled by setting or retrieving widget resources. Many resources are simple integers that do not involve dynamic memory. Others are pointers to memory, e.g., strings, lists, and arrays. For these pointer resources, Motif may allocate dynamic when the resource is set, when the resource is retrieved, in both cases, or in neither case. Let's look at these cases in a little more detail.

Resources can be set either when the widget is first created (XtCreateWidget()) or later with XtSetValues(). For some pointer resources, the widget will copy the value to which the pointer refers. For others, it will save and use the provided pointer. If the value is copied, then the application program should free the original to avoid a memory leak. If the pointer is used internally by the widget, then the application must not free or modify the value or it could corrupt the widget.

Similar issues occur when the application program retrieves resource values with XtGetValues(). For some resources, the widget will create a copy of the value and return a pointer to the copy. For other resources, the widget will return a pointer to the widget's internal memory. If the value is copied, then the application should free it to avoid a memory leak. If it is not copied, then the application must not free the value or it will corrupt internal memory.

In the next section, I'll discuss some general rules about resource memory that apply to many common types of widget resources. The sections after that will cover the individual cases that do not fall in the common classes.

General Rules for Motif Resources

In this section, I'll cover some general rules about dynamic memory and Motif widget resources. These rules apply to all Motif widgets. In the next sections, I'll cover the individual cases that are not covered by these general rules.

Many Motif resources fall into a few similar groups, based on their data type:

Fortunately, Motif treats all resources in each of these groups the same way with respect to dynamic memory. I'll cover each of them in this section.

XmString resources include things like the XmLabel widget's (and its subclasses's) XmNlabelString resource. Motif always copies XmString resources when they are set in the widget's creation or XtSetValues() methods. This means that the application should free its copy to avoid a memory leak.

Note that an important case of the above rule is the XtVaTypedArg token:


char *myString = "hello, world";
int myLen = strlen(myString) + 1;

/* a memory leak */
XtVaSetValues(myLabel,
    XtVaTypedArg, XmNlabelString, XmRString, myString, myLen,
    NULL);


In the above example, Motif's string-to-XmString resource converter will convert the (char *) string to a XmString, but there is no way for the application program to free the XmString. Doing this once will leak only a few bytes of memory, but repeating it many times could affect your program's performance. When I programatically set XmNlabelString's that are based on (char *) strings, I generally use this technique:


XmString xms = XmStringCreateLocalized("hello, world");
XtVaSetValues(myLabel, XmNlabelString, xms, NULL);
XmStringFree(xms);


When applications retrieve XmString resources with XtGetValues(), Motif always copies the XmString's and returns the copies. The application program should be careful to free these copies to avoid memory leaks.

XmFontList resources are handled a little differently from the XmString resources mentioned above. XmFontList resources are also copied when set by XtSetValues(), but they are not copied again when retrieved by XtGetValues(). Application programs must be careful not to free or modify the retrieved values or they may corrupt the Motif widgets.

Pixel and Pixmap resources are widely used for widget graphics. Unlike the resources mentioned above, these data types represent memory stored in the X server as well as in the X client. Server-side memory leaks can be just as important as client-side memory leaks. Motif does not copy these resources, either when set or retrieved, so clients should not modify them after using them in Motif widgets.

XtCallbackList resources are used for a widget's pointers to callback functions. They can be set via the resource functions, though they are usually set by XtAddCallback(). Like the Pixel and Pixmap resources, callback lists are not copied in either XtSetValues() or XtGetValues().

This section has covered the way Motif handles several major types of resources. Motif always handles resources of these types the same ways in its direct resource manipulation functions. Note that Motif may work differently in it's convenience function interfaces, which I'll cover below.

Note also that resources of other types are not handled consistently by Motif. For example, resources with the popular (char *) string resource type are sometimes copied and sometimes not (depending on the particular widget and resource). The next section discusses how application programs should handle resources with this, and other, types.

Specific Widget Resources and Convenience Functions

The next several subsections discuss specific cases where setting or retrieving Motif widget resources allocates dynamic memory that should be freed by the application program. To keep this list to a useful size, I'm won't cover every widget resource. The following are intentionally excluded from this section:

In the following subsections, I'll cover the Motif widgets individually. For each widget, I'll list where the widget allocates dynamic memory during:

I'll try to list all resources and convenience functions that involve dynamic memory (generally arrays and lists, including (char *) strings) and specify:

Note that many Motif widgets inherit behavior (resources and, sometimes, convenience functions) from their superclasses. When you use such behavior, you should check the superclass for information about it.

The Motif widgets are listed below in alphabetical order.


VendorShell

VendorShell is subclassed from WMShell. See that widget for information on inherited resources.

Each widget set, such as Motif, defines its own VendorShell widget class. This material applies only to the Motif VendorShell.

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


TopLevelShell and WMShell

The TopLevelShell and WMShell widgets are part of the X Toolkit intrinsics, not Motif, but I'll list them here because they are commonly used by Motif programmers and have some interesting dynamic memory resources.

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():

Note that the XtNtitle resource does the same thing as the XmBulletinBoard widget's XmNdialogTitle resource. The two differ, however, in the way their memory is handled:

You should be careful not to confuse these two resources.


XmArrowButton and XmArrowButtonGadget

No dynamic memory is allocated.


XmBulletinBoard

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmCascadeButton and XmCascadeButtonGadget

XmCascadeButton and XmCascadeButtonGadget are subclassed from XmLabel and XmLabelGadget. See those widgets for information on inherited resources.

XmCascadeButton and XmCascadeButtonGadget define no new dynamic memory resources.


XmCommand

XmCommand is subclassed from XmSelectionBox. See that widget for information on inherited resources.

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():

The following convenience function copies the input XmString. The application may free its copies.


XmDialogShell

XmDialogShell is subclassed from TransientShell and VendorShell. See those widgets for information on inherited resources.

XmDialogShell defines no new dynamic memory resources.


XmDrawingArea

No dynamic memory is allocated.


XmDrawnButton

XmDrawnButton is subclassed from XmLabel. See that widgets for information on inherited resources.

XmDrawnButton defines no new dynamic memory resources.


XmFileSelectionBox

XmFileSelectionBox is subclassed from XmSelectionBox. See that widget for information on inherited resources.

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmForm

XmForm is subclassed from XmBulletinBoard. See that widget for information on inherited resources.


XmFrame

No dynamic memory is allocated.


XmGadget

No dynamic memory is allocated.


XmLabel and XmLabelGadget

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmList

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():

The following convenience functions copy the new list items. The application may free its copies.

The following convenience functions return a copy of their lists. The application should free the copy.


XmMainWindow

No dynamic memory is allocated.


XmManager

No dynamic memory is allocated.


XmMenuShell

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmMessageBox

XmMessageBox is subclassed from XmBulletinBoard. See that widget for information on inherited resources.

The following resources are copied during both XtSetValues() and XtGetValues():


XmPanedWindow

No dynamic memory is allocated.


XmPushButton and XmPushButtonGadget

XmPushButton and XmPushButtonGadget are subclassed from XmLabel and XmLabelGadget. See those widgets for information on inherited resources.

XmPushButton and XmPushButtonGadget define no new dynamic memory resources.


XmPrimitive

No dynamic memory is allocated.


XmRowColumn

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources can only be set when the widget is created. They cannot be set or retrieved later. They are copied when the widget is created:


XmSash

No dynamic memory is allocated.


XmScale

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmScrollBar

No dynamic memory is allocated.


XmScrolledWindow

No dynamic memory is allocated.


XmSelectionBox

XmSelectionBox is subclassed from XmBulletinBoard. See that widget for information on inherited resources.

The following resources are copied during both XtSetValues() and XtGetValues():

The following resources are copied during XtSetValues(), but not XtGetValues():


XmSeparator and XmSeparatorGadget

No dynamic memory is allocated.


XmTemplateBox

XmFileTemplateBox is subclassed from XmBulletinBoard. See that widget for information on inherited resources.

XmTemplateBox adds no new dynamic memory resources.


XmText and XmTextField

The following resources are copied during both XtSetValues() and XtGetValues():

Note that some tutorial books say that the above return pointers to the internal widget memory. They are wrong.

The following resources are copied during XtSetValues(), but not XtGetValues():

The following convenience functions copy their string input:

The following convenience functions copy their string output into dynamically allocated memory. The application should free the (char *) string with XtFree():

The following convenience functions copy their string output into a buffer provided by the application. If the application allocated the buffer dynamically, it should free it.


XmToggleButton and XmToggleButtonGadget

XmToggleButton and XmToggleButtonGadget are subclassed from XmLabel and XmLabelGadget. See those widgets for information on inherited resources.

XmToggleButton and XmToggleButtonGadget define no new dynamic memory resources.


Motif Convenience Functions

In addition to the widget resources and widget-oriented convenience functions listed above, Motif defines many convenience functions that are not associated with particular widgets. This section describes lists the convenience functions that allocate dynamic memory that should be freed by the application.


Conclusion

In summary, pointer and dynamic memory problems are some of the most common and most serious bugs in C and C++ programs, including X application programs. Last month, we reviewed the most common memory problems and described general techniques to avoid and debug them. This month, we covered specific cases where programmers must be careful with dynamic memory allocated by Motif.

The standard Motif documentation is, unfortunately, often incomplete; I had to read through the Motif source code to get most of this material. Carefully following this material should help you avoid most memory leak problems involving the Motif library.

I recommend that you be especially careful with Motif resources and convenience functions that your programs use repeatedly, e.g., in loops or in input callback functions. Even small leaks in such situations can add up quickly.


References

[Lee6-95]
Kenton Lee, "The X Application Programming Model" The X Advisor, June, 1995.
[Lee2-96]
Kenton Lee, "Memory Leaks and Other Memory Bugs" The X Advisor, February, 1996.
[McCormack]
Joel McCormack, et al, X Toolkit Intrinsics - C Language Reference, included with the X Consortium's X11R6 release.
[OSF]
Open Software Foundation, OSF/Motif Programmer's Reference: Revision 1.2 (for OSF/Motif Release 1.2), Prentice-Hall, 1993.
[Scheifler]
Robert Scheifler and James Gettys, X Window System (third edition), Digital Press, 1992.


The Author

Ken Lee is an independent software consultant specializing in X Window System application software. He has been developing UNIX graphical user interface software since 1981. Ken may be reached by Internet electronic mail at kenton @ rahul.net or on the World Wide Web at http://www.rahul.net/kenton/.

Ken has published over two dozen technical papers on X software development. Most are available over the World Wide Web at http://www.rahul.net/kenton/bib.html.