[libvirt] [PATCH] util: Allow removing hash entries in virHashForEach

Daniel Veillard veillard at redhat.com
Thu Mar 3 14:09:32 UTC 2011


On Thu, Mar 03, 2011 at 02:46:57PM +0100, Jiri Denemark wrote:
> This fixes a possible crash of libvirtd during its startup. When qemu
> driver reconnects to running domains, it iterates over all domain
> objects in a hash. When reconnecting to an associated qemu monitor
> fails and the domain is transient, it's immediately removed from the
> hash. Despite the fact that it's explicitly forbidden to do so. If
> libvirtd is lucky enough, virHashForEach will access random memory when
> the callback finishes and the deamon will crash.
> 
> Since it's trivial to fix virHashForEach to allow removal of hash
> entries while iterating through them, I went this way instead of fixing
> qemuReconnectDomain callback (and possibly others) to avoid deleting the
> entries.
> ---
>  src/util/hash.c |    8 ++++----
>  1 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/src/util/hash.c b/src/util/hash.c
> index 92ee234..2a9a9cf 100644
> --- a/src/util/hash.c
> +++ b/src/util/hash.c
> @@ -548,9 +548,8 @@ virHashRemoveEntry(virHashTablePtr table, const void *name)
>   * @data: opaque data to pass to the iterator
>   *
>   * Iterates over every element in the hash table, invoking the
> - * 'iter' callback. The callback must not call any other virHash*
> - * functions, and in particular must not attempt to remove the
> - * element.
> + * 'iter' callback. The callback is allowed to remove the element using
> + * virHashRemoveEntry but calling other virHash* functions is prohibited.
>   *
>   * Returns number of items iterated over upon completion, -1 on failure
>   */
> @@ -563,11 +562,12 @@ int virHashForEach(virHashTablePtr table, virHashIterator iter, void *data) {
>      for (i = 0 ; i < table->size ; i++) {
>          virHashEntryPtr entry = table->table + i;
>          while (entry) {
> +            virHashEntryPtr next = entry->next;
>              if (entry->valid) {
>                  iter(entry->payload, entry->name, data);
>                  count++;
>              }
> -            entry = entry->next;
> +            entry = next;
>          }
>      }
>      return (count);

  ACK, removing should be safe then, but adding will still be
a big problem due to virHashGrow().

It's a safety belt, but doesn't replace driving properly. I tend to
think we should try to detect reentrant behaviour, for example have
a counter increment each time an operation is done on the hash and
raise a warning at runtime if the counter changed around iter().

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list