All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
@ 2019-07-25  8:43 Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 1/3] glib: bump min required glib library version to 2.48 Daniel P. Berrangé
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2019-07-25  8:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Daniel P. Berrangé

Both GCC and CLang support a C extension attribute((cleanup)) which
allows you to define a function that is invoked when a stack variable
exits scope. This typically used to free the memory allocated to it,
though you're not restricted to this. For example it could be used to
unlock a mutex.

We could use that functionality now, but the syntax is a bit ugly in
plain C. Since version 2.44 of GLib, there have been a few macros to
make it more friendly to use - g_autofree, g_autoptr and
G_DEFINE_AUTOPTR_CLEANUP_FUNC.

  https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html

  https://blogs.gnome.org/desrt/2015/01/30/g_autoptr/

The key selling point is that it simplifies the cleanup code paths,
often eliminating the need to goto cleanup labels. This improves
the readability of the code and makes it less likely that you'll
leak memory accidentally.

Inspired by seeing it added to glib, and used in systemd, Libvirt
finally got around to adopting this in Feb 2019. Overall our
experience with it has been favourable/positive, with the code
simplification being very nice.

The main caveats with it are

 - Only works with GCC or CLang. We don't care as those are
   the only two compilers we declare support for.

 - You must always initialize the variables when declared
   to ensure predictable behaviour when they leave scope.
   Chances are most methods with goto jumps for cleanup
   are doing this already

 - You must not directly return the value that's assigned
   to a auto-cleaned variable. You must steal the pointer
   in some way. ie

    BAD:
        g_autofree char *wibble = g_strdup("wibble")
	....
	return wibble;

    GOOD:
        g_autofree char *wibble = g_strdup("wibble")
	...
	return g_steal_pointer(wibble);

    g_steal_pointer is an inline function which simply copies
    the pointer to a new variable, and sets the original variable
    to NULL, thus avoiding cleanup.

I've illustrated the usage by converting a bunch of the crypto code in
QEMU to use auto cleanup.

Changed on v2:

 - Actually commit the rest of the changes to patch 3 so that what's
   posted works :-) Sigh.

Daniel P. Berrangé (3):
  glib: bump min required glib library version to 2.48
  crypto: define cleanup functions for use with g_autoptr
  crypto: use auto cleanup for many stack variables

 configure                   |  2 +-
 crypto/afsplit.c            | 28 ++++----------
 crypto/block-luks.c         | 74 +++++++++++--------------------------
 crypto/block.c              | 15 +++-----
 crypto/hmac-glib.c          |  5 ---
 crypto/pbkdf.c              |  5 +--
 crypto/secret.c             | 38 ++++++++-----------
 crypto/tlscredsanon.c       | 16 +++-----
 crypto/tlscredspsk.c        |  5 +--
 crypto/tlscredsx509.c       | 16 +++-----
 include/crypto/block.h      |  2 +
 include/crypto/cipher.h     |  2 +
 include/crypto/hmac.h       |  2 +
 include/crypto/ivgen.h      |  2 +
 include/crypto/tlssession.h |  2 +
 include/glib-compat.h       | 42 +--------------------
 16 files changed, 78 insertions(+), 178 deletions(-)

-- 
2.21.0



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 1/3] glib: bump min required glib library version to 2.48
  2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
@ 2019-07-25  8:43 ` Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 2/3] crypto: define cleanup functions for use with g_autoptr Daniel P. Berrangé
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2019-07-25  8:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Daniel P. Berrangé, Stefan Hajnoczi

Per supported platforms doc[1], the various min glib on relevant distros is:

  RHEL-8: 2.56.1
  RHEL-7: 2.50.3
  Debian (Buster): 2.58.3
  Debian (Stretch): 2.50.3
  OpenBSD (Ports): 2.58.3
  FreeBSD (Ports): 2.56.3
  OpenSUSE Leap 15: 2.54.3
  SLE12-SP2: 2.48.2
  Ubuntu (Xenial): 2.48.0
  macOS (Homebrew): 2.56.0

This suggests that a minimum glib of 2.48 is a reasonable target.

Compared to the previous version bump in

  commit e7b3af81597db1a6b55f2c15d030d703c6b2c6ac
  Author: Daniel P. Berrangé <berrange@redhat.com>
  Date:   Fri May 4 15:34:46 2018 +0100

    glib: bump min required glib library version to 2.40

This will result in us dropping support for Debian Jessie and
Ubuntu 14.04.

As per the commit message 14.04 was already outside our list
of supported build platforms and an exception was only made
because one of the build hosts used during merge testing was
stuck on 14.04.

Debian Jessie is justified to drop because we only aim to
support at most 2 major versions of Debian at any time. This
means Buster and Stretch at this time.

The g_strv_contains compat code is dropped as this API is
present since 2.44

The g_assert_cmpmem compat code is dropped as this API is
present since 2.46

[1] https://qemu.weilnetz.de/doc/qemu-doc.html#Supported-build-platforms

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 configure             |  2 +-
 crypto/hmac-glib.c    |  5 -----
 include/glib-compat.h | 42 ++----------------------------------------
 3 files changed, 3 insertions(+), 46 deletions(-)

diff --git a/configure b/configure
index 714e7fb6a1..22dc9c41db 100755
--- a/configure
+++ b/configure
@@ -3636,7 +3636,7 @@ fi
 ##########################################
 # glib support probe
 
-glib_req_ver=2.40
+glib_req_ver=2.48
 glib_modules=gthread-2.0
 if test "$modules" = yes; then
     glib_modules="$glib_modules gmodule-export-2.0"
diff --git a/crypto/hmac-glib.c b/crypto/hmac-glib.c
index 7df627329d..509bbc74c2 100644
--- a/crypto/hmac-glib.c
+++ b/crypto/hmac-glib.c
@@ -21,12 +21,7 @@ static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
     [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
     [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
     [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
-/* Support for HMAC SHA-512 in GLib 2.42 */
-#if GLIB_CHECK_VERSION(2, 42, 0)
     [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
-#else
-    [QCRYPTO_HASH_ALG_SHA512] = -1,
-#endif
     [QCRYPTO_HASH_ALG_SHA224] = -1,
     [QCRYPTO_HASH_ALG_SHA384] = -1,
     [QCRYPTO_HASH_ALG_RIPEMD160] = -1,
diff --git a/include/glib-compat.h b/include/glib-compat.h
index 1291628e09..0b0ec76299 100644
--- a/include/glib-compat.h
+++ b/include/glib-compat.h
@@ -19,12 +19,12 @@
 /* Ask for warnings for anything that was marked deprecated in
  * the defined version, or before. It is a candidate for rewrite.
  */
-#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40
+#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_48
 
 /* Ask for warnings if code tries to use function that did not
  * exist in the defined version. These risk breaking builds
  */
-#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40
+#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_48
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -63,26 +63,6 @@
  * without generating warnings.
  */
 
-static inline gboolean g_strv_contains_qemu(const gchar *const *strv,
-                                            const gchar *str)
-{
-#if GLIB_CHECK_VERSION(2, 44, 0)
-    return g_strv_contains(strv, str);
-#else
-    g_return_val_if_fail(strv != NULL, FALSE);
-    g_return_val_if_fail(str != NULL, FALSE);
-
-    for (; *strv != NULL; strv++) {
-        if (g_str_equal(str, *strv)) {
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-#endif
-}
-#define g_strv_contains(a, b) g_strv_contains_qemu(a, b)
-
 #if defined(_WIN32) && !GLIB_CHECK_VERSION(2, 50, 0)
 /*
  * g_poll has a problem on Windows when using
@@ -92,24 +72,6 @@ static inline gboolean g_strv_contains_qemu(const gchar *const *strv,
 gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout);
 #endif
 
-
-#ifndef g_assert_cmpmem
-#define g_assert_cmpmem(m1, l1, m2, l2)                                        \
-    do {                                                                       \
-        gconstpointer __m1 = m1, __m2 = m2;                                    \
-        int __l1 = l1, __l2 = l2;                                              \
-        if (__l1 != __l2) {                                                    \
-            g_assertion_message_cmpnum(                                        \
-                G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,                   \
-                #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==",   \
-                __l2, 'i');                                                    \
-        } else if (memcmp(__m1, __m2, __l1) != 0) {                            \
-            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
-                                "assertion failed (" #m1 " == " #m2 ")");      \
-        }                                                                      \
-    } while (0)
-#endif
-
 #pragma GCC diagnostic pop
 
 #endif
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 2/3] crypto: define cleanup functions for use with g_autoptr
  2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 1/3] glib: bump min required glib library version to 2.48 Daniel P. Berrangé
@ 2019-07-25  8:43 ` Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables Daniel P. Berrangé
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2019-07-25  8:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Daniel P. Berrangé, Stefan Hajnoczi

Allow crypto structs to be used with g_autoptr, avoiding the need to
explicitly call XXX_free() functions when variables go out of scope on
the stack.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 include/crypto/block.h      | 2 ++
 include/crypto/cipher.h     | 2 ++
 include/crypto/hmac.h       | 2 ++
 include/crypto/ivgen.h      | 2 ++
 include/crypto/tlssession.h | 2 ++
 5 files changed, 10 insertions(+)

diff --git a/include/crypto/block.h b/include/crypto/block.h
index fe12899831..d49d2c2da9 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -268,4 +268,6 @@ uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
  */
 void qcrypto_block_free(QCryptoBlock *block);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
+
 #endif /* QCRYPTO_BLOCK_H */
diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h
index cac90b410c..5928e5ecc7 100644
--- a/include/crypto/cipher.h
+++ b/include/crypto/cipher.h
@@ -170,6 +170,8 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
  */
 void qcrypto_cipher_free(QCryptoCipher *cipher);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoCipher, qcrypto_cipher_free)
+
 /**
  * qcrypto_cipher_encrypt:
  * @cipher: the cipher object
diff --git a/include/crypto/hmac.h b/include/crypto/hmac.h
index aa3c97a2ff..ad4d778416 100644
--- a/include/crypto/hmac.h
+++ b/include/crypto/hmac.h
@@ -65,6 +65,8 @@ QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
  */
 void qcrypto_hmac_free(QCryptoHmac *hmac);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHmac, qcrypto_hmac_free)
+
 /**
  * qcrypto_hmac_bytesv:
  * @hmac: the hmac object
diff --git a/include/crypto/ivgen.h b/include/crypto/ivgen.h
index 9b4a62f7bb..e41521519c 100644
--- a/include/crypto/ivgen.h
+++ b/include/crypto/ivgen.h
@@ -203,4 +203,6 @@ QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
  */
 void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoIVGen, qcrypto_ivgen_free)
+
 #endif /* QCRYPTO_IVGEN_H */
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
index 816300cdcc..e01e1a9dc2 100644
--- a/include/crypto/tlssession.h
+++ b/include/crypto/tlssession.h
@@ -160,6 +160,8 @@ QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds,
  */
 void qcrypto_tls_session_free(QCryptoTLSSession *sess);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
+
 /**
  * qcrypto_tls_session_check_credentials:
  * @sess: the TLS session object
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables
  2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 1/3] glib: bump min required glib library version to 2.48 Daniel P. Berrangé
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 2/3] crypto: define cleanup functions for use with g_autoptr Daniel P. Berrangé
@ 2019-07-25  8:43 ` Daniel P. Berrangé
  2019-07-29 14:58   ` Stefan Hajnoczi
  2019-07-31 12:59 ` [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Marc-André Lureau
  2019-07-31 14:04 ` Alex Bennée
  4 siblings, 1 reply; 10+ messages in thread
From: Daniel P. Berrangé @ 2019-07-25  8:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Daniel P. Berrangé

Simplify cleanup paths by using glib's auto cleanup macros for stack
variables, allowing several goto jumps / labels to be eliminated.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 crypto/afsplit.c      | 28 +++++-----------
 crypto/block-luks.c   | 74 +++++++++++++------------------------------
 crypto/block.c        | 15 +++------
 crypto/pbkdf.c        |  5 +--
 crypto/secret.c       | 38 ++++++++++------------
 crypto/tlscredsanon.c | 16 ++++------
 crypto/tlscredspsk.c  |  5 ++-
 crypto/tlscredsx509.c | 16 +++-------
 8 files changed, 65 insertions(+), 132 deletions(-)

diff --git a/crypto/afsplit.c b/crypto/afsplit.c
index 328d68c96b..b1a5a20899 100644
--- a/crypto/afsplit.c
+++ b/crypto/afsplit.c
@@ -58,7 +58,7 @@ static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
     }
 
     for (i = 0; i < hashcount; i++) {
-        uint8_t *out = NULL;
+        g_autofree uint8_t *out = NULL;
         size_t outlen = 0;
         uint32_t iv = cpu_to_be32(i);
         struct iovec in[] = {
@@ -79,7 +79,6 @@ static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
         assert(outlen == digestlen);
         memcpy(block + (i * digestlen), out,
                (i == (hashcount - 1)) ? finallen : digestlen);
-        g_free(out);
     }
 
     return 0;
@@ -93,13 +92,12 @@ int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
                            uint8_t *out,
                            Error **errp)
 {
-    uint8_t *block = g_new0(uint8_t, blocklen);
+    g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
     size_t i;
-    int ret = -1;
 
     for (i = 0; i < (stripes - 1); i++) {
         if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
-            goto cleanup;
+            return -1;
         }
 
         qcrypto_afsplit_xor(blocklen,
@@ -108,18 +106,14 @@ int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
                             block);
         if (qcrypto_afsplit_hash(hash, blocklen, block,
                                  errp) < 0) {
-            goto cleanup;
+            return -1;
         }
     }
     qcrypto_afsplit_xor(blocklen,
                         in,
                         block,
                         out + (i * blocklen));
-    ret = 0;
-
- cleanup:
-    g_free(block);
-    return ret;
+    return 0;
 }
 
 
@@ -130,9 +124,8 @@ int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
                            uint8_t *out,
                            Error **errp)
 {
-    uint8_t *block = g_new0(uint8_t, blocklen);
+    g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
     size_t i;
-    int ret = -1;
 
     for (i = 0; i < (stripes - 1); i++) {
         qcrypto_afsplit_xor(blocklen,
@@ -141,7 +134,7 @@ int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
                             block);
         if (qcrypto_afsplit_hash(hash, blocklen, block,
                                  errp) < 0) {
-            goto cleanup;
+            return -1;
         }
     }
 
@@ -149,10 +142,5 @@ int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
                         in + (i * blocklen),
                         block,
                         out);
-
-    ret = 0;
-
- cleanup:
-    g_free(block);
-    return ret;
+    return 0;
 }
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 409ab50f20..c8e0a0caa4 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -425,14 +425,13 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                             Error **errp)
 {
     QCryptoBlockLUKS *luks = block->opaque;
-    uint8_t *splitkey;
+    g_autofree uint8_t *splitkey = NULL;
     size_t splitkeylen;
-    uint8_t *possiblekey;
-    int ret = -1;
+    g_autofree uint8_t *possiblekey = NULL;
     ssize_t rv;
-    QCryptoCipher *cipher = NULL;
+    g_autoptr(QCryptoCipher) cipher = NULL;
     uint8_t keydigest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN];
-    QCryptoIVGen *ivgen = NULL;
+    g_autoptr(QCryptoIVGen) ivgen = NULL;
     size_t niv;
 
     if (slot->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) {
@@ -456,7 +455,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                        slot->iterations,
                        possiblekey, masterkeylen,
                        errp) < 0) {
-        goto cleanup;
+        return -1;
     }
 
     /*
@@ -472,7 +471,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                   opaque,
                   errp);
     if (rv < 0) {
-        goto cleanup;
+        return -1;
     }
 
 
@@ -482,7 +481,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                                 possiblekey, masterkeylen,
                                 errp);
     if (!cipher) {
-        goto cleanup;
+        return -1;
     }
 
     niv = qcrypto_cipher_get_iv_len(cipheralg,
@@ -493,7 +492,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                               possiblekey, masterkeylen,
                               errp);
     if (!ivgen) {
-        goto cleanup;
+        return -1;
     }
 
 
@@ -512,7 +511,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                                             splitkey,
                                             splitkeylen,
                                             errp) < 0) {
-        goto cleanup;
+        return -1;
     }
 
     /*
@@ -525,7 +524,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                                splitkey,
                                masterkey,
                                errp) < 0) {
-        goto cleanup;
+        return -1;
     }
 
 
@@ -544,26 +543,18 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
                        luks->header.master_key_iterations,
                        keydigest, G_N_ELEMENTS(keydigest),
                        errp) < 0) {
-        goto cleanup;
+        return -1;
     }
 
     if (memcmp(keydigest, luks->header.master_key_digest,
                QCRYPTO_BLOCK_LUKS_DIGEST_LEN) == 0) {
         /* Success, we got the right master key */
-        ret = 1;
-        goto cleanup;
+        return 1;
     }
 
     /* Fail, user's password was not valid for this key slot,
      * tell caller to try another slot */
-    ret = 0;
-
- cleanup:
-    qcrypto_ivgen_free(ivgen);
-    qcrypto_cipher_free(cipher);
-    g_free(splitkey);
-    g_free(possiblekey);
-    return ret;
+    return 0;
 }
 
 
@@ -644,7 +635,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
     int ret = 0;
     size_t i;
     ssize_t rv;
-    uint8_t *masterkey = NULL;
+    g_autofree uint8_t *masterkey = NULL;
     size_t masterkeylen;
     char *ivgen_name, *ivhash_name;
     QCryptoCipherMode ciphermode;
@@ -653,7 +644,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
     QCryptoCipherAlgorithm ivcipheralg;
     QCryptoHashAlgorithm hash;
     QCryptoHashAlgorithm ivhash;
-    char *password = NULL;
+    g_autofree char *password = NULL;
 
     if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) {
         if (!options->u.luks.key_secret) {
@@ -856,17 +847,12 @@ qcrypto_block_luks_open(QCryptoBlock *block,
     luks->ivgen_hash_alg = ivhash;
     luks->hash_alg = hash;
 
-    g_free(masterkey);
-    g_free(password);
-
     return 0;
 
  fail:
-    g_free(masterkey);
     qcrypto_block_free_cipher(block);
     qcrypto_ivgen_free(block->ivgen);
     g_free(luks);
-    g_free(password);
     return ret;
 }
 
@@ -891,20 +877,20 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     QCryptoBlockLUKS *luks;
     QCryptoBlockCreateOptionsLUKS luks_opts;
     Error *local_err = NULL;
-    uint8_t *masterkey = NULL;
-    uint8_t *slotkey = NULL;
-    uint8_t *splitkey = NULL;
+    g_autofree uint8_t *masterkey = NULL;
+    g_autofree uint8_t *slotkey = NULL;
+    g_autofree uint8_t *splitkey = NULL;
     size_t splitkeylen = 0;
     size_t i;
-    QCryptoCipher *cipher = NULL;
-    QCryptoIVGen *ivgen = NULL;
-    char *password;
+    g_autoptr(QCryptoCipher) cipher = NULL;
+    g_autoptr(QCryptoIVGen) ivgen = NULL;
+    g_autofree char *password;
     const char *cipher_alg;
     const char *cipher_mode;
     const char *ivgen_alg;
     const char *ivgen_hash_alg = NULL;
     const char *hash_alg;
-    char *cipher_mode_spec = NULL;
+    g_autofree char *cipher_mode_spec = NULL;
     QCryptoCipherAlgorithm ivcipheralg = 0;
     uint64_t iters;
 
@@ -1311,15 +1297,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     luks->hash_alg = luks_opts.hash_alg;
 
     memset(masterkey, 0, luks->header.key_bytes);
-    g_free(masterkey);
     memset(slotkey, 0, luks->header.key_bytes);
-    g_free(slotkey);
-    g_free(splitkey);
-    g_free(password);
-    g_free(cipher_mode_spec);
-
-    qcrypto_ivgen_free(ivgen);
-    qcrypto_cipher_free(cipher);
 
     return 0;
 
@@ -1327,17 +1305,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     if (masterkey) {
         memset(masterkey, 0, luks->header.key_bytes);
     }
-    g_free(masterkey);
     if (slotkey) {
         memset(slotkey, 0, luks->header.key_bytes);
     }
-    g_free(slotkey);
-    g_free(splitkey);
-    g_free(password);
-    g_free(cipher_mode_spec);
-
-    qcrypto_ivgen_free(ivgen);
-    qcrypto_cipher_free(cipher);
 
     qcrypto_block_free_cipher(block);
     qcrypto_ivgen_free(block->ivgen);
diff --git a/crypto/block.c b/crypto/block.c
index ee96759f7d..325752871c 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -299,15 +299,13 @@ static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
                                           QCryptoCipherEncDecFunc func,
                                           Error **errp)
 {
-    uint8_t *iv;
+    g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
     int ret = -1;
     uint64_t startsector = offset / sectorsize;
 
     assert(QEMU_IS_ALIGNED(offset, sectorsize));
     assert(QEMU_IS_ALIGNED(len, sectorsize));
 
-    iv = niv ? g_new0(uint8_t, niv) : NULL;
-
     while (len > 0) {
         size_t nbytes;
         if (niv) {
@@ -320,19 +318,19 @@ static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
             }
 
             if (ret < 0) {
-                goto cleanup;
+                return -1;
             }
 
             if (qcrypto_cipher_setiv(cipher,
                                      iv, niv,
                                      errp) < 0) {
-                goto cleanup;
+                return -1;
             }
         }
 
         nbytes = len > sectorsize ? sectorsize : len;
         if (func(cipher, buf, buf, nbytes, errp) < 0) {
-            goto cleanup;
+            return -1;
         }
 
         startsector++;
@@ -340,10 +338,7 @@ static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
         len -= nbytes;
     }
 
-    ret = 0;
- cleanup:
-    g_free(iv);
-    return ret;
+    return 0;
 }
 
 
diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c
index b7c7c4a59b..3775ddc6c5 100644
--- a/crypto/pbkdf.c
+++ b/crypto/pbkdf.c
@@ -69,12 +69,10 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
                                     Error **errp)
 {
     uint64_t ret = -1;
-    uint8_t *out;
+    g_autofree uint8_t *out = g_new(uint8_t, nout);
     uint64_t iterations = (1 << 15);
     unsigned long long delta_ms, start_ms, end_ms;
 
-    out = g_new(uint8_t, nout);
-
     while (1) {
         if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
             goto cleanup;
@@ -108,6 +106,5 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
 
  cleanup:
     memset(out, 0, nout);
-    g_free(out);
     return ret;
 }
diff --git a/crypto/secret.c b/crypto/secret.c
index a75d50ae0c..daab81575f 100644
--- a/crypto/secret.c
+++ b/crypto/secret.c
@@ -72,10 +72,12 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
                                    size_t *outputlen,
                                    Error **errp)
 {
-    uint8_t *key = NULL, *ciphertext = NULL, *iv = NULL;
+    g_autofree uint8_t *key = NULL;
+    g_autofree uint8_t *ciphertext = NULL;
+    g_autofree uint8_t *iv = NULL;
     size_t keylen, ciphertextlen, ivlen;
-    QCryptoCipher *aes = NULL;
-    uint8_t *plaintext = NULL;
+    g_autoptr(QCryptoCipher) aes = NULL;
+    g_autofree uint8_t *plaintext = NULL;
 
     *output = NULL;
     *outputlen = 0;
@@ -83,27 +85,27 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
     if (qcrypto_secret_lookup(secret->keyid,
                               &key, &keylen,
                               errp) < 0) {
-        goto cleanup;
+        return;
     }
 
     if (keylen != 32) {
         error_setg(errp, "Key should be 32 bytes in length");
-        goto cleanup;
+        return;
     }
 
     if (!secret->iv) {
         error_setg(errp, "IV is required to decrypt secret");
-        goto cleanup;
+        return;
     }
 
     iv = qbase64_decode(secret->iv, -1, &ivlen, errp);
     if (!iv) {
-        goto cleanup;
+        return;
     }
     if (ivlen != 16) {
         error_setg(errp, "IV should be 16 bytes in length not %zu",
                    ivlen);
-        goto cleanup;
+        return;
     }
 
     aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
@@ -111,11 +113,11 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
                              key, keylen,
                              errp);
     if (!aes) {
-        goto cleanup;
+        return;
     }
 
     if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) {
-        goto cleanup;
+        return;
     }
 
     if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
@@ -124,7 +126,7 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
                                     &ciphertextlen,
                                     errp);
         if (!ciphertext) {
-            goto cleanup;
+            return;
         }
         plaintext = g_new0(uint8_t, ciphertextlen + 1);
     } else {
@@ -136,8 +138,7 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
                                plaintext,
                                ciphertextlen,
                                errp) < 0) {
-        plaintext = NULL;
-        goto cleanup;
+        return;
     }
 
     if (plaintext[ciphertextlen - 1] > 16 ||
@@ -145,9 +146,7 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
         error_setg(errp, "Incorrect number of padding bytes (%d) "
                    "found on decrypted data",
                    (int)plaintext[ciphertextlen - 1]);
-        g_free(plaintext);
-        plaintext = NULL;
-        goto cleanup;
+        return;
     }
 
     /* Even though plaintext may contain arbitrary NUL
@@ -158,12 +157,7 @@ static void qcrypto_secret_decrypt(QCryptoSecret *secret,
 
     *output = plaintext;
     *outputlen = ciphertextlen;
-
- cleanup:
-    g_free(ciphertext);
-    g_free(iv);
-    g_free(key);
-    qcrypto_cipher_free(aes);
+    plaintext = NULL;
 }
 
 
diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c
index d2adc7c131..a235f60146 100644
--- a/crypto/tlscredsanon.c
+++ b/crypto/tlscredsanon.c
@@ -34,9 +34,8 @@ static int
 qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
                             Error **errp)
 {
-    char *dhparams = NULL;
+    g_autofree char *dhparams = NULL;
     int ret;
-    int rv = -1;
 
     trace_qcrypto_tls_creds_anon_load(creds,
             creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
@@ -45,20 +44,20 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
                                        QCRYPTO_TLS_CREDS_DH_PARAMS,
                                        false, &dhparams, errp) < 0) {
-            goto cleanup;
+            return -1;
         }
 
         ret = gnutls_anon_allocate_server_credentials(&creds->data.server);
         if (ret < 0) {
             error_setg(errp, "Cannot allocate credentials: %s",
                        gnutls_strerror(ret));
-            goto cleanup;
+            return -1;
         }
 
         if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
                                                  &creds->parent_obj.dh_params,
                                                  errp) < 0) {
-            goto cleanup;
+            return -1;
         }
 
         gnutls_anon_set_server_dh_params(creds->data.server,
@@ -68,14 +67,11 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
         if (ret < 0) {
             error_setg(errp, "Cannot allocate credentials: %s",
                        gnutls_strerror(ret));
-            goto cleanup;
+            return -1;
         }
     }
 
-    rv = 0;
- cleanup:
-    g_free(dhparams);
-    return rv;
+    return 0;
 }
 
 
diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c
index 4b6cf636ce..15d12e2448 100644
--- a/crypto/tlscredspsk.c
+++ b/crypto/tlscredspsk.c
@@ -69,7 +69,8 @@ static int
 qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
                            Error **errp)
 {
-    char *pskfile = NULL, *dhparams = NULL;
+    g_autofree char *pskfile = NULL;
+    g_autofree char *dhparams = NULL;
     const char *username;
     int ret;
     int rv = -1;
@@ -139,8 +140,6 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
     rv = 0;
  cleanup:
     g_free(key.data);
-    g_free(pskfile);
-    g_free(dhparams);
     return rv;
 }
 
diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
index 56dcef3673..01fc304e5d 100644
--- a/crypto/tlscredsx509.c
+++ b/crypto/tlscredsx509.c
@@ -378,7 +378,7 @@ qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
 {
     gnutls_datum_t data;
     gnutls_x509_crt_t cert = NULL;
-    char *buf = NULL;
+    g_autofree char *buf = NULL;
     gsize buflen;
     GError *gerr;
     int ret = -1;
@@ -420,7 +420,6 @@ qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
         gnutls_x509_crt_deinit(cert);
         cert = NULL;
     }
-    g_free(buf);
     return cert;
 }
 
@@ -434,9 +433,8 @@ qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
                                     Error **errp)
 {
     gnutls_datum_t data;
-    char *buf = NULL;
+    g_autofree char *buf = NULL;
     gsize buflen;
-    int ret = -1;
     GError *gerr = NULL;
 
     *ncerts = 0;
@@ -446,7 +444,7 @@ qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
         error_setg(errp, "Cannot load CA cert list %s: %s",
                    certFile, gerr->message);
         g_error_free(gerr);
-        goto cleanup;
+        return -1;
     }
 
     data.data = (unsigned char *)buf;
@@ -457,15 +455,11 @@ qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
         error_setg(errp,
                    "Unable to import CA certificate list %s",
                    certFile);
-        goto cleanup;
+        return -1;
     }
     *ncerts = certMax;
 
-    ret = 0;
-
- cleanup:
-    g_free(buf);
-    return ret;
+    return 0;
 }
 
 
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables Daniel P. Berrangé
@ 2019-07-29 14:58   ` Stefan Hajnoczi
  0 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2019-07-29 14:58 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 762 bytes --]

On Thu, Jul 25, 2019 at 09:43:41AM +0100, Daniel P. Berrangé wrote:
> Simplify cleanup paths by using glib's auto cleanup macros for stack
> variables, allowing several goto jumps / labels to be eliminated.
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
>  crypto/afsplit.c      | 28 +++++-----------
>  crypto/block-luks.c   | 74 +++++++++++++------------------------------
>  crypto/block.c        | 15 +++------
>  crypto/pbkdf.c        |  5 +--
>  crypto/secret.c       | 38 ++++++++++------------
>  crypto/tlscredsanon.c | 16 ++++------
>  crypto/tlscredspsk.c  |  5 ++-
>  crypto/tlscredsx509.c | 16 +++-------
>  8 files changed, 65 insertions(+), 132 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 484 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
  2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
                   ` (2 preceding siblings ...)
  2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables Daniel P. Berrangé
@ 2019-07-31 12:59 ` Marc-André Lureau
  2019-07-31 14:04 ` Alex Bennée
  4 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2019-07-31 12:59 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: QEMU

On Thu, Jul 25, 2019 at 12:44 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> Both GCC and CLang support a C extension attribute((cleanup)) which
> allows you to define a function that is invoked when a stack variable
> exits scope. This typically used to free the memory allocated to it,
> though you're not restricted to this. For example it could be used to
> unlock a mutex.
>
> We could use that functionality now, but the syntax is a bit ugly in
> plain C. Since version 2.44 of GLib, there have been a few macros to
> make it more friendly to use - g_autofree, g_autoptr and
> G_DEFINE_AUTOPTR_CLEANUP_FUNC.
>
>   https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html
>
>   https://blogs.gnome.org/desrt/2015/01/30/g_autoptr/
>
> The key selling point is that it simplifies the cleanup code paths,
> often eliminating the need to goto cleanup labels. This improves
> the readability of the code and makes it less likely that you'll
> leak memory accidentally.
>
> Inspired by seeing it added to glib, and used in systemd, Libvirt
> finally got around to adopting this in Feb 2019. Overall our
> experience with it has been favourable/positive, with the code
> simplification being very nice.
>
> The main caveats with it are
>
>  - Only works with GCC or CLang. We don't care as those are
>    the only two compilers we declare support for.
>
>  - You must always initialize the variables when declared
>    to ensure predictable behaviour when they leave scope.
>    Chances are most methods with goto jumps for cleanup
>    are doing this already
>
>  - You must not directly return the value that's assigned
>    to a auto-cleaned variable. You must steal the pointer
>    in some way. ie
>
>     BAD:
>         g_autofree char *wibble = g_strdup("wibble")
>         ....
>         return wibble;
>
>     GOOD:
>         g_autofree char *wibble = g_strdup("wibble")
>         ...
>         return g_steal_pointer(wibble);
>
>     g_steal_pointer is an inline function which simply copies
>     the pointer to a new variable, and sets the original variable
>     to NULL, thus avoiding cleanup.
>
> I've illustrated the usage by converting a bunch of the crypto code in
> QEMU to use auto cleanup.
>
> Changed on v2:
>
>  - Actually commit the rest of the changes to patch 3 so that what's
>    posted works :-) Sigh.
>
> Daniel P. Berrangé (3):
>   glib: bump min required glib library version to 2.48
>   crypto: define cleanup functions for use with g_autoptr
>   crypto: use auto cleanup for many stack variables

Series:
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

>
>  configure                   |  2 +-
>  crypto/afsplit.c            | 28 ++++----------
>  crypto/block-luks.c         | 74 +++++++++++--------------------------
>  crypto/block.c              | 15 +++-----
>  crypto/hmac-glib.c          |  5 ---
>  crypto/pbkdf.c              |  5 +--
>  crypto/secret.c             | 38 ++++++++-----------
>  crypto/tlscredsanon.c       | 16 +++-----
>  crypto/tlscredspsk.c        |  5 +--
>  crypto/tlscredsx509.c       | 16 +++-----
>  include/crypto/block.h      |  2 +
>  include/crypto/cipher.h     |  2 +
>  include/crypto/hmac.h       |  2 +
>  include/crypto/ivgen.h      |  2 +
>  include/crypto/tlssession.h |  2 +
>  include/glib-compat.h       | 42 +--------------------
>  16 files changed, 78 insertions(+), 178 deletions(-)
>
> --
> 2.21.0
>
>


-- 
Marc-André Lureau


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
  2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
                   ` (3 preceding siblings ...)
  2019-07-31 12:59 ` [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Marc-André Lureau
@ 2019-07-31 14:04 ` Alex Bennée
  2019-07-31 14:08   ` Eric Blake
  2019-07-31 14:10   ` Daniel P. Berrangé
  4 siblings, 2 replies; 10+ messages in thread
From: Alex Bennée @ 2019-07-31 14:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Daniel P. Berrangé


Daniel P. Berrangé <berrange@redhat.com> writes:

> Both GCC and CLang support a C extension attribute((cleanup)) which
> allows you to define a function that is invoked when a stack variable
> exits scope. This typically used to free the memory allocated to it,
> though you're not restricted to this. For example it could be used to
> unlock a mutex.
<snip>
>
>     GOOD:
>         g_autofree char *wibble = g_strdup("wibble")
> 	...
> 	return g_steal_pointer(wibble);
>
>     g_steal_pointer is an inline function which simply copies
>     the pointer to a new variable, and sets the original variable
>     to NULL, thus avoiding cleanup.

Surely this is a particular use case where you wouldn't use g_autofree
to declare the variable as you intending to return it to the outer scope?

--
Alex Bennée


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
  2019-07-31 14:04 ` Alex Bennée
@ 2019-07-31 14:08   ` Eric Blake
  2019-07-31 14:10   ` Daniel P. Berrangé
  1 sibling, 0 replies; 10+ messages in thread
From: Eric Blake @ 2019-07-31 14:08 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: Daniel P. Berrangé


[-- Attachment #1.1: Type: text/plain, Size: 1251 bytes --]

On 7/31/19 9:04 AM, Alex Bennée wrote:
> 
> Daniel P. Berrangé <berrange@redhat.com> writes:
> 
>> Both GCC and CLang support a C extension attribute((cleanup)) which
>> allows you to define a function that is invoked when a stack variable
>> exits scope. This typically used to free the memory allocated to it,
>> though you're not restricted to this. For example it could be used to
>> unlock a mutex.
> <snip>
>>
>>     GOOD:
>>         g_autofree char *wibble = g_strdup("wibble")
>> 	...
>> 	return g_steal_pointer(wibble);
>>
>>     g_steal_pointer is an inline function which simply copies
>>     the pointer to a new variable, and sets the original variable
>>     to NULL, thus avoiding cleanup.
> 
> Surely this is a particular use case where you wouldn't use g_autofree
> to declare the variable as you intending to return it to the outer scope?

Actually, it's still quite useful if you have intermediate returns:

g_autofree char *wibble = NULL;
if (something)
  return NULL;
wibble = g_strdup("wibble");
if (something_else)
  return NULL;
return g_steal_pointer(wibble);

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
  2019-07-31 14:04 ` Alex Bennée
  2019-07-31 14:08   ` Eric Blake
@ 2019-07-31 14:10   ` Daniel P. Berrangé
  2019-07-31 14:33     ` Alex Bennée
  1 sibling, 1 reply; 10+ messages in thread
From: Daniel P. Berrangé @ 2019-07-31 14:10 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel

On Wed, Jul 31, 2019 at 03:04:29PM +0100, Alex Bennée wrote:
> 
> Daniel P. Berrangé <berrange@redhat.com> writes:
> 
> > Both GCC and CLang support a C extension attribute((cleanup)) which
> > allows you to define a function that is invoked when a stack variable
> > exits scope. This typically used to free the memory allocated to it,
> > though you're not restricted to this. For example it could be used to
> > unlock a mutex.
> <snip>
> >
> >     GOOD:
> >         g_autofree char *wibble = g_strdup("wibble")
> > 	...
> > 	return g_steal_pointer(wibble);
> >
> >     g_steal_pointer is an inline function which simply copies
> >     the pointer to a new variable, and sets the original variable
> >     to NULL, thus avoiding cleanup.
> 
> Surely this is a particular use case where you wouldn't use g_autofree
> to declare the variable as you intending to return it to the outer scope?

I think it depends on the situation. Obviously real code will have
something in the "..." part I snipped.

You have 20 code paths that can result in returning with an error, where
you want to have all variables freed, and only 1 code path for success
Then it makes sense to use g_autofree + g_steal_pointer to eliminate
many goto jumps.

If you have only 1 error path and 1 success path, then a traditional
g_free() call is may well be sufficient.

IOW, as with many coding "rules", there's scope to use personal
judgement as to when it is right to ignore it vs folow it.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope
  2019-07-31 14:10   ` Daniel P. Berrangé
@ 2019-07-31 14:33     ` Alex Bennée
  0 siblings, 0 replies; 10+ messages in thread
From: Alex Bennée @ 2019-07-31 14:33 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: qemu-devel


Daniel P. Berrangé <berrange@redhat.com> writes:

> On Wed, Jul 31, 2019 at 03:04:29PM +0100, Alex Bennée wrote:
>>
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>>
>> > Both GCC and CLang support a C extension attribute((cleanup)) which
>> > allows you to define a function that is invoked when a stack variable
>> > exits scope. This typically used to free the memory allocated to it,
>> > though you're not restricted to this. For example it could be used to
>> > unlock a mutex.
>> <snip>
>> >
>> >     GOOD:
>> >         g_autofree char *wibble = g_strdup("wibble")
>> > 	...
>> > 	return g_steal_pointer(wibble);
>> >
>> >     g_steal_pointer is an inline function which simply copies
>> >     the pointer to a new variable, and sets the original variable
>> >     to NULL, thus avoiding cleanup.
>>
>> Surely this is a particular use case where you wouldn't use g_autofree
>> to declare the variable as you intending to return it to the outer scope?
>
> I think it depends on the situation. Obviously real code will have
> something in the "..." part I snipped.
>
> You have 20 code paths that can result in returning with an error, where
> you want to have all variables freed, and only 1 code path for success
> Then it makes sense to use g_autofree + g_steal_pointer to eliminate
> many goto jumps.
>
> If you have only 1 error path and 1 success path, then a traditional
> g_free() call is may well be sufficient.

I suspect this would be worth a write up in HACKING or CODING_STYLE with
the next iteration? (which reminds me we should really merge and .rst up
those documents)

>
> IOW, as with many coding "rules", there's scope to use personal
> judgement as to when it is right to ignore it vs folow it.
>
> Regards,
> Daniel


--
Alex Bennée


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-07-31 14:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-25  8:43 [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Daniel P. Berrangé
2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 1/3] glib: bump min required glib library version to 2.48 Daniel P. Berrangé
2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 2/3] crypto: define cleanup functions for use with g_autoptr Daniel P. Berrangé
2019-07-25  8:43 ` [Qemu-devel] [PATCH v2 3/3] crypto: use auto cleanup for many stack variables Daniel P. Berrangé
2019-07-29 14:58   ` Stefan Hajnoczi
2019-07-31 12:59 ` [Qemu-devel] [PATCH v2 0/3] require newer glib2 to enable autofree'ing of stack variables exiting scope Marc-André Lureau
2019-07-31 14:04 ` Alex Bennée
2019-07-31 14:08   ` Eric Blake
2019-07-31 14:10   ` Daniel P. Berrangé
2019-07-31 14:33     ` Alex Bennée

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.