Some libvirt functions were wrapped using a Java String as return
type, although they return a "char*". That means the memory allocated
by libvirt for those strings is never freed because JNA assumes a
"const char*".
Start to refactor the String handling by using a type-safe Pointer for
C Strings, which automatically frees the memory when converting from
the native pointer to the Java type.
---
src/main/java/org/libvirt/Connect.java | 17 +++---
src/main/java/org/libvirt/Device.java | 2 +-
src/main/java/org/libvirt/NetworkFilter.java | 2 +-
src/main/java/org/libvirt/Secret.java | 2 +-
src/main/java/org/libvirt/StoragePool.java | 2 +-
src/main/java/org/libvirt/jna/CString.java | 85 ++++++++++++++++++++++++++++
src/main/java/org/libvirt/jna/Libvirt.java | 18 +++---
7 files changed, 108 insertions(+), 20 deletions(-)
create mode 100644 src/main/java/org/libvirt/jna/CString.java
diff --git a/src/main/java/org/libvirt/Connect.java
b/src/main/java/org/libvirt/Connect.java
index e86fd83..d0bdc4d 100644
--- a/src/main/java/org/libvirt/Connect.java
+++ b/src/main/java/org/libvirt/Connect.java
@@ -7,6 +7,7 @@ import java.util.UUID;
import org.libvirt.event.*;
import org.libvirt.jna.ConnectionPointer;
+import org.libvirt.jna.CString;
import org.libvirt.jna.DevicePointer;
import org.libvirt.jna.DomainPointer;
import org.libvirt.jna.InterfacePointer;
@@ -364,7 +365,8 @@ public class Connect {
* @throws LibvirtException
*/
public String baselineCPU(String[] xmlCPUs) throws LibvirtException {
- return processError(libvirt.virConnectBaselineCPU(VCP, xmlCPUs, xmlCPUs.length,
0));
+ CString result = libvirt.virConnectBaselineCPU(VCP, xmlCPUs, xmlCPUs.length, 0);
+ return processError(result).toString();
}
/**
@@ -920,7 +922,8 @@ public class Connect {
* @throws LibvirtException
*/
public String domainXMLFromNative(String nativeFormat, String nativeConfig, int
flags) throws LibvirtException {
- return processError(libvirt.virConnectDomainXMLFromNative(VCP, nativeFormat,
nativeConfig, 0));
+ CString result = libvirt.virConnectDomainXMLFromNative(VCP, nativeFormat,
nativeConfig, 0);
+ return processError(result).toString();
}
/**
@@ -932,8 +935,8 @@ public class Connect {
* @throws LibvirtException
*/
public String domainXMLToNative(String nativeFormat, String domainXML, int flags)
throws LibvirtException {
- String returnValue = libvirt.virConnectDomainXMLToNative(VCP, nativeFormat,
domainXML, 0);
- return processError(returnValue);
+ CString returnValue = libvirt.virConnectDomainXMLToNative(VCP, nativeFormat,
domainXML, 0);
+ return processError(returnValue).toString();
}
@Override
@@ -962,8 +965,8 @@ public class Connect {
* @throws LibvirtException
*/
public String findStoragePoolSources(String type, String srcSpecs, int flags) throws
LibvirtException {
- String returnValue = libvirt.virConnectFindStoragePoolSources(VCP, type,
srcSpecs, flags);
- return processError(returnValue);
+ CString returnValue = libvirt.virConnectFindStoragePoolSources(VCP, type,
srcSpecs, flags);
+ return processError(returnValue).toString();
}
/**
@@ -1109,7 +1112,7 @@ public class Connect {
* @throws LibvirtException
*/
public String getURI() throws LibvirtException {
- return processError(libvirt.virConnectGetURI(VCP));
+ return processError(libvirt.virConnectGetURI(VCP)).toString();
}
/**
diff --git a/src/main/java/org/libvirt/Device.java
b/src/main/java/org/libvirt/Device.java
index 3c876c6..04f373e 100644
--- a/src/main/java/org/libvirt/Device.java
+++ b/src/main/java/org/libvirt/Device.java
@@ -118,7 +118,7 @@ public class Device {
* @throws LibvirtException
*/
public String getXMLDescription() throws LibvirtException {
- return processError(libvirt.virNodeDeviceGetXMLDesc(VDP, 0));
+ return processError(libvirt.virNodeDeviceGetXMLDesc(VDP, 0)).toString();
}
/**
diff --git a/src/main/java/org/libvirt/NetworkFilter.java
b/src/main/java/org/libvirt/NetworkFilter.java
index 4f4bc6c..094a5f6 100644
--- a/src/main/java/org/libvirt/NetworkFilter.java
+++ b/src/main/java/org/libvirt/NetworkFilter.java
@@ -90,7 +90,7 @@ public class NetworkFilter {
* @return the XML document
*/
public String getXMLDesc() throws LibvirtException {
- return processError(libvirt.virNWFilterGetXMLDesc(NFP, 0));
+ return processError(libvirt.virNWFilterGetXMLDesc(NFP, 0)).toString();
}
/**
diff --git a/src/main/java/org/libvirt/Secret.java
b/src/main/java/org/libvirt/Secret.java
index e0ded73..a5f13ac 100644
--- a/src/main/java/org/libvirt/Secret.java
+++ b/src/main/java/org/libvirt/Secret.java
@@ -127,7 +127,7 @@ public class Secret {
* @return the XML document
*/
public String getXMLDesc() throws LibvirtException {
- return processError(libvirt.virSecretGetXMLDesc(VSP, 0));
+ return processError(libvirt.virSecretGetXMLDesc(VSP, 0)).toString();
}
/**
diff --git a/src/main/java/org/libvirt/StoragePool.java
b/src/main/java/org/libvirt/StoragePool.java
index 14ecab8..8caf9f5 100644
--- a/src/main/java/org/libvirt/StoragePool.java
+++ b/src/main/java/org/libvirt/StoragePool.java
@@ -207,7 +207,7 @@ public class StoragePool {
* @return a XML document -java @throws LibvirtException
*/
public String getXMLDesc(int flags) throws LibvirtException {
- return processError(libvirt.virStoragePoolGetXMLDesc(VSPP, flags));
+ return processError(libvirt.virStoragePoolGetXMLDesc(VSPP, flags)).toString();
}
/**
diff --git a/src/main/java/org/libvirt/jna/CString.java
b/src/main/java/org/libvirt/jna/CString.java
new file mode 100644
index 0000000..b6d9dc2
--- /dev/null
+++ b/src/main/java/org/libvirt/jna/CString.java
@@ -0,0 +1,85 @@
+package org.libvirt.jna;
+
+import java.nio.charset.Charset;
+
+import com.sun.jna.FromNativeContext;
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.PointerType;
+
+/**
+ * Represents an allocated C-String.
+ * <p>
+ * Either call {@link #toString} or {@link #free()}. Both methods make
+ * sure to reclaim the memory allocated for the string by calling
+ * Native.free.
+ */
+public class CString extends PointerType {
+ // all strings in libvirt are UTF-8 encoded
+ private final static Charset UTF8 = Charset.forName("UTF-8");
+ private final static byte NUL = 0;
+ private String string = null;
+
+ public CString() {
+ super();
+ }
+
+ public CString(Pointer p) {
+ super(p);
+ }
+
+ /**
+ * Returns a String representing the value of this C-String
+ * <p>
+ * Side-effect: frees the memory of the C-String.
+ */
+ @Override
+ public String toString() {
+ if (string == null) {
+ final Pointer ptr = getPointer();
+
+ if (ptr == null) return null;
+
+ try {
+ // N.B. could be replaced with Pointer.getString(0L, "UTF-8")
+ // available in JNA >= 4.x
+ final long len = ptr.indexOf(0, NUL);
+ assert (len != -1): "C-Strings must be \\0 terminated.";
+ assert (len <= Integer.MAX_VALUE): "string length exceeded "
+ Integer.MAX_VALUE;
+
+ if (len == 0) {
+ string = "";
+ } else {
+ final byte[] data = ptr.getByteArray(0, (int)len);
+
+ string = new String(data, UTF8);
+ }
+ } finally {
+ free(ptr);
+ }
+ }
+ return string;
+ }
+
+ @Override
+ public CString fromNative(Object nativeValue, FromNativeContext context) {
+ if (nativeValue == null) return null;
+
+ return new CString((Pointer)nativeValue);
+ }
+
+ private void free(Pointer ptr) {
+ assert ptr != null;
+
+ Native.free(Pointer.nativeValue(ptr));
+ setPointer(null);
+ }
+
+ /**
+ * Free the memory used by this C-String
+ */
+ public void free() {
+ final Pointer ptr = getPointer();
+ if (ptr != null) free(ptr);
+ }
+}
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java
b/src/main/java/org/libvirt/jna/Libvirt.java
index a3cee0a..5a176b0 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -150,7 +150,7 @@ public interface Libvirt extends Library {
public static int VIR_DOMAIN_SCHED_FIELD_LENGTH = 80;
// Connection Functions
- String virConnectBaselineCPU(ConnectionPointer virConnectPtr, String[] xmlCPUs, int
ncpus, int flags);
+ CString virConnectBaselineCPU(ConnectionPointer virConnectPtr, String[] xmlCPUs, int
ncpus, int flags);
/**
* @deprecated as of libvirt 0.6.0, all errors reported in the
@@ -175,14 +175,14 @@ public interface Libvirt extends Library {
int virConnectIsAlive(ConnectionPointer virConnectPtr);
int virConnectIsEncrypted(ConnectionPointer virConnectPtr) ;
int virConnectIsSecure(ConnectionPointer virConnectPtr) ;
- String virConnectFindStoragePoolSources(ConnectionPointer virConnectPtr, String type,
String srcSpec, int flags);
+ CString virConnectFindStoragePoolSources(ConnectionPointer virConnectPtr, String
type, String srcSpec, int flags);
Pointer virConnectGetCapabilities(ConnectionPointer virConnectPtr);
Pointer virConnectGetHostname(ConnectionPointer virConnectPtr);
int virConnectGetLibVersion(ConnectionPointer virConnectPtr, LongByReference
libVer);
int virConnectGetMaxVcpus(ConnectionPointer virConnectPtr, String type);
Pointer virConnectGetSysinfo(ConnectionPointer virConnectPtr, int flags);
String virConnectGetType(ConnectionPointer virConnectPtr);
- String virConnectGetURI(ConnectionPointer virConnectPtr);
+ CString virConnectGetURI(ConnectionPointer virConnectPtr);
int virConnectGetVersion(ConnectionPointer virConnectPtr, LongByReference hvVer);
int virConnectListDefinedDomains(ConnectionPointer virConnectPtr, Pointer[] name, int
maxnames);
int virConnectListDefinedNetworks(ConnectionPointer virConnectPtr, Pointer[] name,
int maxnames);
@@ -218,9 +218,9 @@ public interface Libvirt extends Library {
@Deprecated
virError virConnGetLastError(ConnectionPointer virConnectPtr);
void virConnResetLastError(ConnectionPointer virConnectPtr);
- String virConnectDomainXMLFromNative(ConnectionPointer virConnectPtr, String
nativeFormat,
+ CString virConnectDomainXMLFromNative(ConnectionPointer virConnectPtr, String
nativeFormat,
String nativeConfig, int flags);
- String virConnectDomainXMLToNative(ConnectionPointer virConnectPtr, String
nativeFormat, String domainXML,
+ CString virConnectDomainXMLToNative(ConnectionPointer virConnectPtr, String
nativeFormat, String domainXML,
int flags);
// Global functions
@@ -350,7 +350,7 @@ public interface Libvirt extends Library {
String virNodeDeviceGetParent(DevicePointer virDevicePointer);
int virNodeDeviceNumOfCaps(DevicePointer virDevicePointer);
int virNodeDeviceListCaps(DevicePointer virDevicePointer, Pointer[] names, int
maxNames);
- String virNodeDeviceGetXMLDesc(DevicePointer virDevicePointer, int flags);
+ CString virNodeDeviceGetXMLDesc(DevicePointer virDevicePointer, int flags);
int virNodeDeviceFree(DevicePointer virDevicePointer);
int virNodeDeviceDettach(DevicePointer virDevicePointer);
int virNodeDeviceReAttach(DevicePointer virDevicePointer);
@@ -371,7 +371,7 @@ public interface Libvirt extends Library {
String virStoragePoolGetName(StoragePoolPointer storagePoolPtr);
int virStoragePoolGetUUID(StoragePoolPointer storagePoolPtr, byte[] uuidString);
int virStoragePoolGetUUIDString(StoragePoolPointer storagePoolPtr, byte[]
uuidString);
- String virStoragePoolGetXMLDesc(StoragePoolPointer storagePoolPtr, int flags);
+ CString virStoragePoolGetXMLDesc(StoragePoolPointer storagePoolPtr, int flags);
int virStoragePoolListVolumes(StoragePoolPointer storagePoolPtr, Pointer[] names, int
maxnames);
int virStoragePoolIsActive(StoragePoolPointer storagePoolPtr);
int virStoragePoolIsPersistent(StoragePoolPointer storagePoolPtr);
@@ -422,7 +422,7 @@ public interface Libvirt extends Library {
String virSecretGetUsageID(SecretPointer virSecretPtr);
int virSecretGetUsageType(SecretPointer virSecretPtr);
Pointer virSecretGetValue(SecretPointer virSecretPtr, SizeTByReference value_size,
int flags);
- String virSecretGetXMLDesc(SecretPointer virSecretPtr, int flags);
+ CString virSecretGetXMLDesc(SecretPointer virSecretPtr, int flags);
SecretPointer virSecretLookupByUsage(ConnectionPointer virConnectPtr, int usageType,
String usageID);
SecretPointer virSecretLookupByUUID(ConnectionPointer virConnectPtr, byte[]
uuidBytes);
SecretPointer virSecretLookupByUUIDString(ConnectionPointer virConnectPtr, String
uuidstr);
@@ -455,7 +455,7 @@ public interface Libvirt extends Library {
int virDomainSnapshotNum(DomainPointer virDomainPtr, int flags);
// Network Filter Methods
- String virNWFilterGetXMLDesc(NetworkFilterPointer virNWFilterPtr, int flags);
+ CString virNWFilterGetXMLDesc(NetworkFilterPointer virNWFilterPtr, int flags);
NetworkFilterPointer virNWFilterDefineXML(ConnectionPointer virConnectPtr, String
xml);
int virNWFilterFree(NetworkFilterPointer virNWFilterPtr);
NetworkFilterPointer virNWFilterLookupByName(ConnectionPointer virConnectPtr, String
name);
--
2.2.2