From 889755296a5dc795d524af0d2a0ed87fa53d128e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 18:04:32 +0100 Subject: [PATCH 1/6] iio.h: Update iio_context_get_xml() Instead of returning a string allocated alongside the IIO context, it will now return a string allocated on the heap, that has to be freed with free() afterwards. The function can now also return errors. The advantage of this change is multiple: - IIO contexts now don't have a huge XML string allocated during their whole lifetime; - If the application does not call iio_context_get_xml(), then all the internal functions used to generate the XML string in the first place are dead code, and when building statically, can be garbage-collected. Signed-off-by: Paul Cercueil --- context.c | 15 ++------------- iio-private.h | 2 -- include/iio/iio.h | 5 +++-- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/context.c b/context.c index 601ef2a93..a129ce821 100644 --- a/context.c +++ b/context.c @@ -181,7 +181,7 @@ static ssize_t iio_snprintf_context_xml(char *ptr, ssize_t len, } /* Returns a string containing the XML representation of this context */ -static char * iio_context_create_xml(const struct iio_context *ctx) +char * iio_context_get_xml(const struct iio_context *ctx) { ssize_t len; char *str; @@ -251,11 +251,6 @@ void iio_context_set_pdata(struct iio_context *ctx, struct iio_context_pdata *d) ctx->pdata = d; } -const char * iio_context_get_xml(const struct iio_context *ctx) -{ - return ctx->xml; -} - const char * iio_context_get_name(const struct iio_context *ctx) { return ctx->name; @@ -284,7 +279,6 @@ void iio_context_destroy(struct iio_context *ctx) for (i = 0; i < ctx->nb_devices; i++) free_device(ctx->devices[i]); free(ctx->devices); - free(ctx->xml); free(ctx->description); free(ctx->git_tag); free(ctx->pdata); @@ -340,12 +334,7 @@ int iio_context_init(struct iio_context *ctx) for (i = 0; i < ctx->nb_devices; i++) reorder_channels(ctx->devices[i]); - if (ctx->xml) - return 0; - - ctx->xml = iio_context_create_xml(ctx); - - return iio_err(ctx->xml); + return 0; } unsigned int iio_context_get_version_major(const struct iio_context *ctx) diff --git a/iio-private.h b/iio-private.h index 575b5ac73..f6c3a1c00 100644 --- a/iio-private.h +++ b/iio-private.h @@ -92,8 +92,6 @@ struct iio_context { struct iio_device **devices; unsigned int nb_devices; - char *xml; - char **values; struct iio_attr_list attrlist; diff --git a/include/iio/iio.h b/include/iio/iio.h index 708f71e49..6a353230e 100644 --- a/include/iio/iio.h +++ b/include/iio/iio.h @@ -601,8 +601,9 @@ __api __pure const char * iio_context_get_version_tag(const struct iio_context * /** @brief Obtain a XML representation of the given context * @param ctx A pointer to an iio_context structure - * @return A pointer to a static NULL-terminated string */ -__api __check_ret __pure const char * iio_context_get_xml(const struct iio_context *ctx); + * @return On success, an allocated string. Must be deallocated with free(). + * @return On failure, a pointer-encoded error is returned */ +__api __check_ret char * iio_context_get_xml(const struct iio_context *ctx); /** @brief Get the name of the given context From a74f3e7a6ff2e4fa3c12581d8a1dda17019e0b73 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 18:08:55 +0100 Subject: [PATCH 2/6] compat: Pre-allocate XML string for contexts Emulate the v0.x behaviour of iio_context_get_xml() by allocating the XML string when the Libiio context is created; which means that the compatibility layer's iio_context_get_xml() is still a "pure" function. Signed-off-by: Paul Cercueil --- compat.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compat.c b/compat.c index 351d81af5..ae493f9d1 100644 --- a/compat.c +++ b/compat.c @@ -72,7 +72,7 @@ struct compat { const char * (*iio_context_get_name)(const struct iio_context *); const char * (*iio_context_get_description)(const struct iio_context *); - const char * (*iio_context_get_xml)(const struct iio_context *); + char * (*iio_context_get_xml)(const struct iio_context *); const struct iio_context_params * (*iio_context_get_params)(const struct iio_context *); @@ -260,6 +260,7 @@ struct iio_context_compat { void *userdata; unsigned int nb_devices; + char *xml; }; struct iio_buffer_compat { @@ -322,6 +323,11 @@ static int iio_init_context_compat(struct iio_context *ctx) if (!compat) return -ENOMEM; + compat->xml = IIO_CALL(iio_context_get_xml)(ctx); + err = iio_err(compat->xml); + if (err) + goto err_free_compat; + compat->nb_devices = nb_devices; for (i = 0; i < nb_devices; i++) { @@ -368,6 +374,8 @@ static int iio_init_context_compat(struct iio_context *ctx) if (dev_compat->mask) IIO_CALL(iio_channels_mask_destroy)(dev_compat->mask); } + free(compat->xml); +err_free_compat: free(compat); return err; } @@ -442,6 +450,7 @@ void iio_context_destroy(struct iio_context *ctx) compat = IIO_CALL(iio_context_get_data)(ctx); IIO_CALL(iio_context_destroy)(ctx); + free(compat->xml); free(compat); } @@ -694,7 +703,9 @@ const char * iio_context_get_description(const struct iio_context *ctx) const char * iio_context_get_xml(const struct iio_context *ctx) { - return IIO_CALL(iio_context_get_xml)(ctx); + struct iio_context_compat *compat = IIO_CALL(iio_context_get_data)(ctx); + + return compat->xml; } unsigned int iio_context_get_devices_count(const struct iio_context *ctx) From 4d511a9e91c349e1d09bfaeb44ad7d3f19f63362 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 19:19:11 +0100 Subject: [PATCH 3/6] utils: iio_genxml: Free XML string after use Now that iio_context_get_xml() returns a heap-allocated string, we need to de-allocate it with free() after use. Signed-off-by: Paul Cercueil --- utils/iio_genxml.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/iio_genxml.c b/utils/iio_genxml.c index 9f2aaa796..ca7ff5321 100644 --- a/utils/iio_genxml.c +++ b/utils/iio_genxml.c @@ -31,8 +31,7 @@ static const char *options_descriptions[] = { int main(int argc, char **argv) { - char **argw, *uri; - const char *xml; + char **argw, *uri, *xml; struct iio_context *ctx; struct option *opts; size_t buf_len; @@ -84,12 +83,14 @@ int main(int argc, char **argv) uri = malloc(buf_len); if (!uri) { iio_context_destroy(ctx); + free(xml); return EXIT_FAILURE; } snprintf(uri, buf_len, "xml:%s", xml); iio_context_destroy(ctx); + free(xml); ctx = iio_create_context(NULL, uri); if (!ctx) { From 4e3556f3b8c6eff0f1a6fc22c5524abfce846fd3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 19:20:05 +0100 Subject: [PATCH 4/6] iiod: Free XML string after use Now that iio_context_get_xml() returns a heap-allocated string, we need to de-allocate it with free() after use. Signed-off-by: Paul Cercueil --- iiod/iiod.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iiod/iiod.c b/iiod/iiod.c index dba7f17b7..1fc7227b3 100644 --- a/iiod/iiod.c +++ b/iiod/iiod.c @@ -101,19 +101,22 @@ static void sig_handler_usr1(int sig) static void *get_xml_zstd_data(const struct iio_context *ctx, size_t *out_len) { - const char *xml = iio_context_get_xml(ctx); - size_t xml_len = strlen(xml); + char *xml = iio_context_get_xml(ctx); + size_t len, xml_len = strlen(xml); void *buf; #if WITH_ZSTD - size_t len; size_t ret; len = ZSTD_compressBound(xml_len); buf = malloc(len); - if (!buf) + if (!buf) { + free(xml); return NULL; + } ret = ZSTD_compress(buf, len, xml, xml_len, 3); + free(xml); + if (ZSTD_isError(ret)) { IIO_WARNING("Unable to compress XML string: %s\n", ZSTD_getErrorName(xml_len)); @@ -123,10 +126,7 @@ static void *get_xml_zstd_data(const struct iio_context *ctx, size_t *out_len) *out_len = ret; #else - buf = iio_strdup(xml); - if (!buf) - return NULL; - + buf = xml; *out_len = xml_len; #endif From 18a3ca970ad37058bcdb7e2aa56c4c8ad29f7cad Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 19:21:58 +0100 Subject: [PATCH 5/6] python: Free XML string after use Now that iio_context_get_xml() returns a heap-allocated string, we need to de-allocate it with free() after use. Signed-off-by: Paul Cercueil --- bindings/python/iio.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bindings/python/iio.py b/bindings/python/iio.py index e289f56bf..0923f2369 100644 --- a/bindings/python/iio.py +++ b/bindings/python/iio.py @@ -31,6 +31,7 @@ c_double, cast, sizeof, + string_at, POINTER as _POINTER, CDLL as _cdll, memmove as _memmove, @@ -300,6 +301,7 @@ class ChannelType(Enum): _iiolib = "iio" _lib = _cdll("libiio.so.1", use_errno=True, use_last_error=True) +_libc = _cdll(find_library("c")) _get_backends_count = _lib.iio_get_builtin_backends_count _get_backends_count.restype = c_uint @@ -357,7 +359,7 @@ class ChannelType(Enum): _get_description.argtypes = (_ContextPtr,) _get_xml = _lib.iio_context_get_xml -_get_xml.restype = c_char_p +_get_xml.restype = c_void_p _get_xml.argtypes = (_ContextPtr,) _get_version_major = _lib.iio_context_get_version_major @@ -697,6 +699,9 @@ class ChannelType(Enum): _ev_get_channel.argtypes = (_EventPtr, _DevicePtr, c_bool) _ev_get_channel.errcheck = _check_null +_libc_free = _libc.free +_libc_free.argtypes = (c_void_p,) + # pylint: enable=invalid-name @@ -1419,13 +1424,15 @@ def __init__(self, _context=None): self._name = _get_name(self._context).decode("ascii") self._description = _get_description(self._context).decode("ascii") - self._xml = _get_xml(self._context).decode("ascii") + self._xml_hdl = _get_xml(self._context) + self._xml = bytes(string_at(self._xml_hdl)).decode("ascii") self._version = _get_lib_version(self._context) def __del__(self): """Destroy this context.""" if self._context is not None: _destroy(self._context) + _libc_free(cast(self._xml_hdl, c_void_p)) def set_timeout(self, timeout): """ From 79ffd4c3b9cdf3354da311a47291e2e0a8aca462 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jan 2024 19:37:21 +0100 Subject: [PATCH 6/6] c++: Free XML string after use Now that iio_context_get_xml() returns a heap-allocated string, we need to de-allocate it with free() after use. Signed-off-by: Paul Cercueil --- bindings/cpp/iiopp.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/cpp/iiopp.h b/bindings/cpp/iiopp.h index c50256145..617e8c125 100644 --- a/bindings/cpp/iiopp.h +++ b/bindings/cpp/iiopp.h @@ -81,6 +81,7 @@ class cstr public: cstr(std::string const & s) : s(s.c_str()){} cstr(char const * s) : s(s){assert(s);} + cstr(void const * s) : s(static_cast(s)){assert(s);} char const * c_str() const {return s;} operator char const * () const {return s;} @@ -580,6 +581,8 @@ class Device : public impl::IndexedSequence uint32_t reg_read(uint32_t address) {uint32_t value; impl::check(iio_device_reg_read(p, address, &value), "iio_device_reg_read"); return value;} }; +typedef Ptr CstrPtr; + /** @brief C++ wrapper for the @ref Context C-API */ class Context : public impl::IndexedSequence @@ -617,7 +620,7 @@ class Context : public impl::IndexedSequence unsigned int version_major() const { return iio_context_get_version_major(p); } unsigned int version_minor() const { return iio_context_get_version_minor(p); } cstr version_tag() const { return iio_context_get_version_tag(p); } - cstr xml() const { return iio_context_get_xml(p); } + CstrPtr xml() const { return CstrPtr{impl::check(iio_context_get_xml(p), "iio_context_get_xml")};} cstr name() const { return iio_context_get_name(p); } cstr description() const { return iio_context_get_description(p); } unsigned int attrs_count() const {return iio_context_get_attrs_count(p);}