[Libvir] [PATCH] Fix the function that remove the element of the hash table.

Hiroyuki Kaguchi fj7025cf at aa.jp.fujitsu.com
Tue Jan 29 02:32:04 UTC 2008


There are two logic error and a unnecessary else-statement
in virHashRemoveSet function.

This patch fix the following.
(1/3) The logic error that use released memory area.
(2/3) The logic error that doesn't remove elements.
(3/3) Unnecessary else-statement.

(1/3) The logic error that use released memory area.
This bug causes the crash of virt-manager or virsh.
If "virsh undefine" command is executed, "Segmentation Fault" is caused.

The result of executing "valgrind virsh" command is:
virsh # list --all
==3337== Invalid read of size 4
==3337==    at 0x4016A21: virHashRemoveSet (hash.c:562)
==3337==    by 0x403ACF4: xenXMConfigCacheRefresh (xm_internal.c:458)
==3337==    by 0x4040D58: xenXMNumOfDefinedDomains (xm_internal.c:2518)
==3337==    by 0x40245C3: xenUnifiedNumOfDefinedDomains (xen_unified.c:1004)
==3337==    by 0x4013730: virConnectNumOfDefinedDomains (libvirt.c:2446)
==3337==    by 0x804AE81: cmdList (virsh.c:577)
==3337==    by 0x8052E6E: vshCommandRun (virsh.c:4052)
==3337==    by 0x8054E2D: main (virsh.c:5036)
==3337==  Address 0x4282AB8 is 0 bytes inside a block of size 16 free'd
==3337==    at 0x4004FDA: free (vg_replace_malloc.c:233)
==3337==    by 0x40169A0: virHashRemoveSet (hash.c:545)
==3337==    by 0x403ACF4: xenXMConfigCacheRefresh (xm_internal.c:458)
==3337==    by 0x4040D58: xenXMNumOfDefinedDomains (xm_internal.c:2518)
==3337==    by 0x40245C3: xenUnifiedNumOfDefinedDomains (xen_unified.c:1004)
==3337==    by 0x4013730: virConnectNumOfDefinedDomains (libvirt.c:2446)
==3337==    by 0x804AE81: cmdList (virsh.c:577)
==3337==    by 0x8052E6E: vshCommandRun (virsh.c:4052)
==3337==    by 0x8054E2D: main (virsh.c:5036)

The current removing logic is:
1. search for node that be removed in the hash table.
   The removing cursor(pointer) point to "element-B".
 +-hash table---+
 | +----------+ |   +----------+   +----------+
 | |element-A |-|-->|element-B |-->|element-C |
 | +----------+ |   +----------+   +----------+
 | |element-D | |
 | +----------+ |
 | .            |
 | .            |
 +--------------+

2. free "element-B".
   The removing cursor point to invalid address
 +-hash table---+
 | +----------+ |   +----------+
 | |element-A |-|-->|element-C |
 | +----------+ |   +----------+
 | |element-D | |
 | +----------+ |
 | .            |
 | .            |
 +--------------+

3. try to move the removing cursor to next node.
   At this time, the error occurs.


(2/3) The logic error that doesn't remove elements.

The current removing logic is:
1. search for node that will be removed in the hash table.
   The removing cursor point to "element-A".
 +-hash table---+
 | +----------+ |   +----------+   +----------+
 | |element-A |-|-->|element-B |-->|element-C |
 | +----------+ |   +----------+   +----------+
 | |element-D | |
 | +----------+ |
 | .            |
 | .            |
 +--------------+

2. copy "element-B" to "element-A".
 +-hash table---+
 | +----------+ |   +----------+   +----------+
 | |element-B'|-|-->|element-B |-->|element-C |
 | +----------+ |   +----------+   +----------+
 | |element-D | |
 | +----------+ |
 | .            |
 | .            |
 +--------------+

3. remove "element-B"
   The removing cursor point to "element-D".
   "element-C" is skipped.
 +-hash table---+
 | +----------+ |   +----------+
 | |element-B'|-|-->|element-C |
 | +----------+ |   +----------+
 | |element-D | |
 | +----------+ |
 | .            |
 | .            |
 +--------------+

(3/3) Unnecessary else-statement.
There is else-statement that set NULL to the NULL pointer.

Thanks,
Hiroyuki Kaguchi

Index: hash.c
===================================================================
RCS file: /data/cvs/libvirt/src/hash.c,v
retrieving revision 1.27
diff -u -r1.27 hash.c
--- hash.c	21 Jan 2008 16:29:10 -0000	1.27
+++ hash.c	28 Jan 2008 06:48:09 -0000
@@ -543,6 +543,7 @@
                 if (prev) {
                     prev->next = entry->next;
                     free(entry);
+                    entry = prev;
                 } else {
                     if (entry->next == NULL) {
                         entry->valid = 0;
@@ -553,6 +554,7 @@
                                sizeof(virHashEntry));
                         free(entry);
                         entry = NULL;
+                        i--;
                     }
                 }
                 table->nbElems--;
@@ -560,8 +562,6 @@
             prev = entry;
             if (entry) {
                 entry = entry->next;
-            } else {
-                entry = NULL;
             }
         }
     }







More information about the libvir-list mailing list