When doing low level X11 programming it is usually necessary to call XFree() on returned structures. For example XGetWMName, I've done this in the following code, which then blows up after a few seconds with
AssertionMessage: *** Error in `/opt/jdk1.8.0_40/bin/java': double free or corruption (fasttop): 0x00007f7ca822bdd0 ***
This is caused by the XFree() call, if that is removed the problem disappears. However monitoring the process with top shows steady memory growth suggesting I do need it...
public class X11WindowFinder {
private X11 x11;
public X11WindowFinder() {
x11 = X11.INSTANCE;
}
public List<Window> find(Pattern title) {
Display display = x11.XOpenDisplay(null);
Window root = x11.XDefaultRootWindow(display);
List<Window> windows = recurse(x11, display, root, title);
x11.XCloseDisplay(display);
return windows;
}
private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
List<Window> windows = new ArrayList<>(1);
X11.WindowByReference windowRef = new X11.WindowByReference();
X11.WindowByReference parentRef = new X11.WindowByReference();
PointerByReference childrenRef = new PointerByReference();
IntByReference childCountRef = new IntByReference();
x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
if (childrenRef.getValue() == null) {
return Collections.emptyList();
}
long[] ids = {};
if (Native.LONG_SIZE == Long.BYTES) {
ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
} else if (Native.LONG_SIZE == Integer.BYTES) {
int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
ids = new long[intIds.length];
for (int i = 0; i < intIds.length; i++) {
ids[i] = intIds[i];
}
}
for (long id : ids) {
Window child = new Window(id);
X11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
String value = name.value;
if (value != null) {
System.out.println(String.format("Found window %s free %s", value, name));
}
if (value != null && pattern.matcher(value).matches()) {
windows.add(child);
}
x11.XFree(name.getPointer());
windows.addAll(recurse(x11, display, child, pattern));
}
return windows;
}
public static void main(String[] args) {
X11WindowFinder finder = new X11WindowFinder();
while (true) {
finder.find(Pattern.compile(".*Firefox.*"));
}
}
}
The pointers in JNA appear to use finalize() to free memory i.e. com.sun.jna.Memory.finalize()
/** Properly dispose of native memory when this object is GC'd. */
protected void finalize() {
dispose();
}
So if I call XFree() I risk it being double deallocated... Is this assumption correct. I can find few examples of JNA, especially X11 platform related.
You want to free the pointer in the value
field of the XTextProperty
structure, not the structure itself.
From the XTextProperty man page:
To free the storage for the value field, use XFree.
From your code (note that the value
field should be a Pointer
rather than a String
):
x11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
// ... do some stuff
x11.XFree(name.getPointer());
EDIT
Note that with the current definition of XTextProperty
, The value
field is mapped to Java String
, which effectively hides the original pointer. You'd need to use XTextProperty.getPointer(XXX)
(where XXX is the offset of the value
field) in order to access the original pointer value to pass to XFree
. Since the value
field comes first in the struct, using the base address of the Structure
itself will also work (i.e. Structure.getPointer()
).
This call to XFree
should really be part of the XTextProperty
's own memory cleanup (finalizer).