[libvirt] PATCH: 1/4: Add OOM hooks to the memory allocator

Daniel P. Berrange berrange at redhat.com
Thu May 22 17:17:27 UTC 2008


This patch adds extra code to src/memory.c which allows us to force an OOM
condition on specific allocations. This is not code you *ever* want to use
in a production build, so its all conditional on TEST_OOM, which is enabled
by passing  --enable-test-oom to the configure script.

The hooks work as follows...

 - The test suite first calls  virAllocTestInit() to initialize the hooks.
   This causes it to start counting allocations.

 ....then run the code you want to check for OOM...

 - Next call virAllocTestCount() to find out how many allocations were 
   made.

 - Given a number of allocations 'n', we need to repeat 'n' times...

       - Call virAllocTestOOM(n, m) to tell it to fail the n'th allocation
         upto the (n + m -1)'th allocation. eg,  virAllocTestOOM(3, 2)
         will cause allocations 3 and 4 to fail.

        ... run the code you want to check and verify it reports OOM
        in the way you expect.


It can be quite hard to find out just where allocation failure bugs are
hiding. So there is also a virAllocTestHook() function which lets you
register a callback to be invoked at the time an allocation is artificially
failed. Obvious use for this is to capture a stack trace.

 configure.in |   29 +++++++++++++++++++++--
 src/memory.c |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/memory.h |   11 +++++++-
 3 files changed, 109 insertions(+), 5 deletions(-)

Regards,
Daniel

diff -r 9f962ac84b09 configure.in
--- a/configure.in	Wed May 21 19:42:55 2008 -0400
+++ b/configure.in	Wed May 21 22:22:47 2008 -0400
@@ -883,19 +883,39 @@
 AM_CONDITIONAL([ENABLE_XEN_TESTS], [test "$RUNNING_XEN" != "no" -a "$RUNNING_XEND" != "no"])
 
 AC_ARG_ENABLE([test-coverage],
-[  --enable-test-coverage   turn on code coverage instrumentation],
+[  --enable-test-coverage  turn on code coverage instrumentation],
 [case "${enableval}" in
    yes|no) ;;
    *)      AC_MSG_ERROR([bad value ${enableval} for test-coverage option]) ;;
  esac],
               [enableval=no])
+enable_coverage=$enableval
 
-if test "${enableval}" = yes; then
+if test "${enable_coverage}" = yes; then
   gl_COMPILER_FLAGS(-fprofile-arcs)
   gl_COMPILER_FLAGS(-ftest-coverage)
   AC_SUBST([COVERAGE_CFLAGS], [$COMPILER_FLAGS])
   AC_SUBST([COVERAGE_LDFLAGS], [$COMPILER_FLAGS])
   COMPILER_FLAGS=
+fi
+
+AC_ARG_ENABLE([test-oom],
+[  --enable-test-oom       memory allocation failure checking],
+[case "${enableval}" in
+   yes|no) ;;
+   *)      AC_MSG_ERROR([bad value ${enableval} for test-oom option]) ;;
+ esac],
+              [enableval=no])
+enable_oom=$enableval
+
+if test "${enable_oom}" = yes; then
+  have_trace=yes
+  AC_CHECK_HEADER([execinfo.h],[],[have_trace=no])
+  AC_CHECK_FUNC([backtrace],[],[have_trace=no])
+  if test "$have_trace" = "yes"; then
+    AC_DEFINE([HAVE_TRACE], 1, [Whether backtrace() is available])
+  fi
+  AC_DEFINE([TEST_OOM], 1, [Whether malloc OOM checking is enabled])
 fi
 
 dnl Enable building the proxy?
@@ -1042,6 +1062,11 @@
 AC_MSG_NOTICE([  numactl: no])
 fi
 AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Test suite])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([  Coverage: $enable_coverage])
+AC_MSG_NOTICE([  Alloc OOM: $enable_oom])
+AC_MSG_NOTICE([])
 AC_MSG_NOTICE([Miscellaneous])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([  Debug: $enable_debug])
diff -r 9f962ac84b09 src/memory.c
--- a/src/memory.c	Wed May 21 19:42:55 2008 -0400
+++ b/src/memory.c	Wed May 21 22:22:47 2008 -0400
@@ -26,6 +26,59 @@
 #include "memory.h"
 
 
+#if TEST_OOM
+static int testMallocNext = 0;
+static int testMallocFailFirst = 0;
+static int testMallocFailLast = 0;
+static void (*testMallocHook)(void*) = NULL;
+static void *testMallocHookData = NULL;
+
+void virAllocTestInit(void)
+{
+    testMallocNext = 1;
+    testMallocFailFirst = 0;
+    testMallocFailLast = 0;
+}
+
+int virAllocTestCount(void)
+{
+    return testMallocNext - 1;
+}
+
+void virAllocTestHook(void (*func)(void*), void *data)
+{
+    testMallocHook = func;
+    testMallocHookData = data;
+}
+
+void virAllocTestOOM(int n, int m)
+{
+    testMallocNext = 1;
+    testMallocFailFirst = n;
+    testMallocFailLast = n + m - 1;
+}
+
+static int virAllocTestFail(void)
+{
+    int fail = 0;
+    if (testMallocNext == 0)
+        return 0;
+
+    fail =
+        testMallocNext >= testMallocFailFirst &&
+        testMallocNext <= testMallocFailLast;
+
+    //printf("Alloc %d  %d in [%d-%d]\n", fail, testMallocNext, testMallocFailFirst, testMallocFailLast);
+
+    if (fail && testMallocHook)
+        (testMallocHook)(testMallocHookData);
+
+    testMallocNext++;
+    return fail;
+}
+#endif
+
+
 /* Return 1 if an array of N objects, each of size S, cannot exist due
    to size arithmetic overflow.  S must be positive and N must be
    nonnegative.  This is a macro, not an inline function, so that it
@@ -55,12 +108,17 @@
  */
 int virAlloc(void *ptrptr, size_t size)
 {
+#if TEST_OOM
+    if (virAllocTestFail()) {
+        *(void **)ptrptr = NULL;
+        return -1;
+    }
+#endif
+
     if (size == 0) {
         *(void **)ptrptr = NULL;
         return 0;
     }
-
-
 
     *(void **)ptrptr = calloc(1, size);
     if (*(void **)ptrptr == NULL)
@@ -83,6 +141,13 @@
  */
 int virAllocN(void *ptrptr, size_t size, size_t count)
 {
+#if TEST_OOM
+    if (virAllocTestFail()) {
+        *(void **)ptrptr = NULL;
+        return -1;
+    }
+#endif
+
     if (size == 0 || count == 0) {
         *(void **)ptrptr = NULL;
         return 0;
@@ -111,6 +176,11 @@
 int virReallocN(void *ptrptr, size_t size, size_t count)
 {
     void *tmp;
+#if TEST_OOM
+    if (virAllocTestFail())
+        return -1;
+#endif
+
     if (size == 0 || count == 0) {
         free(*(void **)ptrptr);
         *(void **)ptrptr = NULL;
diff -r 9f962ac84b09 src/memory.h
--- a/src/memory.h	Wed May 21 19:42:55 2008 -0400
+++ b/src/memory.h	Wed May 21 22:22:47 2008 -0400
@@ -30,7 +30,6 @@
 int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
 int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
 void virFree(void *ptrptr);
-
 
 /**
  * VIR_ALLOC:
@@ -79,4 +78,14 @@
  */
 #define VIR_FREE(ptr) virFree(&(ptr));
 
+
+#if TEST_OOM
+void virAllocTestInit(void);
+int virAllocTestCount(void);
+void virAllocTestOOM(int n, int m);
+void virAllocTestHook(void (*func)(void*), void *data);
+#endif
+
+
+
 #endif /* __VIR_MEMORY_H_ */


-- 
|: Red Hat, Engineering, Boston   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list