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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list