Like most other things I do, this started as a distraction from something else. I noticed that a function that took a virBufferPtr as an argument was clearing that buffer on error, but most (but *not all*) of its callers (which were the creators/owners of said virBuffer) were already clearing the buffer object on error anyway. Here's the original patch resulting from my seeing this in one place: https://www.redhat.com/archives/libvir-list/2020-June/msg01163.html In the example I saw, eliminating the extra clearing of the virBuffer in the subordinate function would simplify the error-cleanup code for that function, but it turned out the calling function *wasn't* clearing the virBuffer when an error occurred. Looking further, I saw this same pattern occurred in other places in the code - a function would create a new buffer (with "virBuffer buf = VIR_BUFFER_INITIALIZER;"), and clear/free that buffer when it was finished *unless there was an error*, in which case some functions would properly clear the buffer, and some would just return, I guess assuming the caller that generated the error had cleared the buffer. This not only makes the error cleanup logic in subordinate functions messier, it seems philosophically wrong to me, it also sounds like a memory leak just waiting to happen. So I decided that the way it should more properly work is this: 1) all virBuffers should be declared with g_auto(virBuffer), so that they are automatically cleared (with virBufferFreeAndReset()) when that toplevel function declaring/initializing the buffer returns to its caller. 2) subordinate functions called with the virBuffer object as an arg should just leave the buffer in whatever state it was when the error occurred. Since those functions don't use the virBuffer after the error happens, and the caller doesn't look at anything in the virBuffer to determine an error has occurred, this is completely safe. (obvious exceptions to (2) are of course those functions whose main intent is in fact to consume the virBuffer, e.g. virBufferContentAndReset(), and virCommandAddArgBuffer()) Patches 01 - 15 handle part (1) - *all* declarations of virBuffer as an automatic are changed to g_auto(virBuffer), and any virBufferFreeAndReset() calls in those same functions are removed. (I have it split into so many patches because virBuffer is used all over the place, and I figured it would make it easier to backport just one part of the entire set if needed when backported some unrelated bugfix that only touched one of the many directories represented here. I would happily squash together any group of patches anyone wants, however). Patches 16 and 17 fix a couple "one-off" anomolies in the code related to virBuffers. Patch 18 then takes care of point (2) above, by removing any extraneous virBufferFreeAndReset() calls in subordinate functions that are no longer necessary due to the guarantee that the toplevel will cleanup after error. Patches 19-30 just eliminate any labels (and associated "ret" variables and "goto's) that have been rendered pointless by removal of virBufferFreeAndReset(). Finally Patches 31 and 32 convert all usages of virFirewall to use g_autoptr(). They are included in this same set because virFirewall objects are often declared right next to virBuffer objects, so doing those patches in a different order would have caused merge conflicts.. NB: In many of the cases where "virBuffer" was changed to "g_auto(virBuffer)", it doesn't actually eliminate any code from the function, due to the function *always* calling virBufferContentAndReset() anyway. I considered not changing those cases, but in the ended decided it was better to add g_auto() even in those cases for two reasons: 1) consistency makes verification easier, and means someone a year from now won't come up with the same idea and waste time verifying all those cases of virBuffer don't need g_auto(). 2) if those functions ever change to have an alternate return that doesn't explicitly call virBufferContentAndReset(), they will still be safe. 3) the extra overhead is very minimal; a small price to pay for (1) and (2) NB2: these patches aren't just academic code churning; they have fixed some actual (well, theoretically actual) memory leaks, I just haven't taken the time to try and track all of them down or document them, because they only occur in error cases which will likely never happen. One example from my notes: virStoragePoolSaveState calls virStoragePoolDefFormatBuf which calls virStoragePoolSourceFormat, which errors, returns virStoragePoolDefFormatBuf, returns virStoragePoolSaveState returns without freeing virBuffer Laine Stump (32): bhyve: use g_auto() for all virBuffers esx: use g_auto() for all virBuffers hyperv: use g_auto() for all virBuffers libxl: use g_auto() for all virBuffers lxc: use g_auto() for all virBuffers qemu: use g_auto() for all virBuffers tests: use g_auto for all virBuffers tools: use g_auto() for all virBuffers conf: use g_auto() for all virBuffers util: use g_auto() for all virBuffers cpu: use g_auto() for all virBuffers rpc: use g_auto() for all virBuffers nwfilter: use g_auto() for all virBuffers network: use g_auto() for all virBuffers use g_auto() for all remaining non-g_auto() virBuffers qemu: remove unnecessary virBufferFreeAndReset() after virCommandAddArgBuffer() conf: consistently check for error when calling virSysinfoFormat() remove redundant calls to virBufferFreeAndReset() libxml: eliminate extra copy of string bhyve: eliminate unnecessary labels conf: eliminate unnecessary labels libxl: eliminate unnecessary labels util: eliminate unnecessary labels tests: eliminate unnecessary labels tools: eliminate unnecessary labels network: eliminate unnecessary labels lxc: eliminate unnecessary labels esx: eliminate unnecessary labels nwfilter: eliminate unnecessary labels storage: eliminate unnecessary labels use g_autoptr() for all usages of virFirewallNew/Free eliminate unnecessary labels and ret variables src/bhyve/bhyve_command.c | 40 +++--- src/bhyve/bhyve_driver.c | 4 +- src/conf/capabilities.c | 13 +- src/conf/checkpoint_conf.c | 11 +- src/conf/cpu_conf.c | 27 ++-- src/conf/domain_addr.c | 2 +- src/conf/domain_capabilities.c | 2 +- src/conf/domain_conf.c | 105 +++++++------- src/conf/interface_conf.c | 7 +- src/conf/network_conf.c | 8 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.c | 12 +- src/conf/secret_conf.c | 8 +- src/conf/snapshot_conf.c | 14 +- src/conf/storage_capabilities.c | 6 +- src/conf/storage_conf.c | 28 ++-- src/conf/virnetworkobj.c | 10 +- src/conf/virnetworkportdef.c | 6 +- src/conf/virnwfilterbindingdef.c | 6 +- src/conf/virnwfilterbindingobj.c | 6 +- src/conf/virsavecookie.c | 8 +- src/cpu/cpu_map.c | 2 +- src/cpu/cpu_x86.c | 6 +- src/esx/esx_driver.c | 19 +-- src/esx/esx_util.c | 4 +- src/esx/esx_vi.c | 28 ++-- src/esx/esx_vi_methods.c | 6 +- src/hyperv/hyperv_driver.c | 34 +++-- src/hyperv/hyperv_wmi.c | 11 +- src/hypervisor/domain_driver.c | 7 +- src/libxl/libxl_conf.c | 19 +-- src/libxl/libxl_driver.c | 2 +- src/libxl/libxl_migration.c | 2 +- src/libxl/xen_common.c | 28 ++-- src/libxl/xen_xl.c | 45 ++---- src/libxl/xen_xm.c | 10 +- src/locking/lock_driver_sanlock.c | 2 +- src/lxc/lxc_container.c | 4 +- src/lxc/lxc_controller.c | 12 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.c | 3 +- src/network/bridge_driver.c | 25 ++-- src/network/bridge_driver_linux.c | 36 ++--- src/node_device/node_device_udev.c | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 160 +++++++++------------- src/nwfilter/nwfilter_gentech_driver.c | 6 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_driver.c | 5 +- src/qemu/qemu_agent.c | 2 +- src/qemu/qemu_block.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_command.c | 5 +- src/qemu/qemu_dbus.c | 2 +- src/qemu/qemu_domain.c | 4 +- src/qemu/qemu_driver.c | 5 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_migration_cookie.c | 6 +- src/qemu/qemu_monitor.c | 2 +- src/rpc/virnetclient.c | 4 +- src/rpc/virnetlibsshsession.c | 7 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/security/virt-aa-helper.c | 4 +- src/storage/storage_backend_rbd.c | 7 +- src/storage/storage_util.c | 14 +- src/util/virbitmap.c | 4 +- src/util/vircommand.c | 3 +- src/util/virconf.c | 5 +- src/util/virdnsmasq.c | 6 +- src/util/virebtables.c | 24 +--- src/util/virfile.c | 2 +- src/util/virfilecache.c | 2 +- src/util/virfirewall.c | 2 +- src/util/viriptables.c | 14 +- src/util/virlog.c | 5 +- src/util/virnetdevip.c | 3 +- src/util/virpidfile.c | 2 +- src/util/virqemu.c | 11 +- src/util/virresctrl.c | 10 +- src/util/virsocketaddr.c | 25 ++-- src/util/virstoragefile.c | 2 +- src/util/virstring.c | 4 +- src/util/virsysinfo.c | 5 +- src/util/virsystemd.c | 4 +- src/util/viruri.c | 2 +- src/util/virxml.c | 12 +- src/vmx/vmx.c | 5 +- src/vz/vz_driver.c | 4 +- tests/commandtest.c | 3 +- tests/cputest.c | 2 +- tests/networkxml2firewalltest.c | 3 +- tests/nodedevmdevctltest.c | 6 +- tests/nwfilterebiptablestest.c | 21 +-- tests/nwfilterxml2firewalltest.c | 3 +- tests/qemublocktest.c | 2 +- tests/qemucommandutiltest.c | 2 +- tests/qemumigparamstest.c | 6 +- tests/qemumonitorjsontest.c | 9 +- tests/qemumonitortestutils.c | 2 +- tests/testutils.c | 2 +- tests/vboxsnapshotxmltest.c | 3 +- tests/virbuftest.c | 58 ++++---- tests/vircgrouptest.c | 3 +- tests/virfirewalltest.c | 80 +++-------- tests/virhostcputest.c | 3 +- tests/virkmodtest.c | 4 +- tests/virnetdevbandwidthtest.c | 3 +- tools/virsh-checkpoint.c | 3 +- tools/virsh-domain-monitor.c | 3 +- tools/virsh-domain.c | 58 ++++---- tools/virsh-pool.c | 19 ++- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 3 +- tools/virsh-volume.c | 3 +- tools/vsh-table.c | 2 +- tools/vsh.c | 15 +- 116 files changed, 505 insertions(+), 853 deletions(-) -- 2.25.4