From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xen.org
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Subject: [PATCH 10/31] libxl: Crash (more sensibly) on malloc failure
Date: Tue, 10 Apr 2012 20:07:44 +0100 [thread overview]
Message-ID: <1334084885-14474-11-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1334084885-14474-1-git-send-email-ian.jackson@eu.citrix.com>
Formally change the libxl memory allocation failure policy to "crash".
Previously we had a very uneven approach; much code assumed that
libxl__sprintf (for example) would never return NULL, but some code
was written more carefully.
We think it is unlikely that we will be able to make the library
actually robust against allocation failure (since that would be an
awful lot of never-tested error paths) and few calling environments
will be able to cope anyway. So, instead, adopt the alternative
approach: provide allocation functions which never return null, but
will crash the whole process instead.
Consequently,
- New noreturn function libxl__alloc_failed which may be used for
printing a vaguely-useful error message, rather than simply
dereferencing a null pointer.
- libxl__ptr_add now returns void as it crashes on failure.
- libxl__zalloc, _calloc, _strdup, _strndup, crash on failure using
libxl__alloc_failed. So all the code that uses these can no longer
dereference null on malloc failure.
While we're at it, make libxl__ptr_add use realloc rather than
emulating it with calloc and free, and make it grow the array
exponentially rather than linearly.
Things left to do:
- Provide versions of malloc, realloc and free which do the
checking but which do not enroll the pointer in the gc.
- Remove a lot of now-spurious error handling.
- Remove the ERROR_NOMEM error code.
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
tools/libxl/libxl.h | 4 ++
tools/libxl/libxl_internal.c | 87 ++++++++++++++++++++---------------------
tools/libxl/libxl_internal.h | 8 +++-
3 files changed, 53 insertions(+), 46 deletions(-)
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 2aec910..0219f81 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -194,6 +194,10 @@
* No temporary objects allocated from the pool may be explicitly freed.
* Therefore public functions which initialize a libxl__gc MUST call
* libxl__free_all() before returning.
+ *
+ * Memory allocation failures are not handled gracefully. If malloc
+ * (or realloc) fails, libxl will cause the entire process to print
+ * a message to stderr and exit with status 255.
*/
/*
* libxl types
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index 12c32dc..2270234 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -17,40 +17,45 @@
#include "libxl_internal.h"
-int libxl__error_set(libxl__gc *gc, int code)
-{
- return 0;
+void libxl__alloc_failed(libxl_ctx *ctx, const char *func,
+ size_t nmemb, size_t size) {
+#define M "libxl: FATAL ERROR: memory allocation failure"
+#define L (size ? M " (%s, %lu x %lu)\n" : M " (%s)\n"), \
+ func, (unsigned long)nmemb, (unsigned long)size
+ libxl__log(ctx, XTL_CRITICAL, ENOMEM, 0,0, func, L);
+ fprintf(stderr, L);
+ fflush(stderr);
+ _exit(-1);
+#undef M
+#undef L
}
-int libxl__ptr_add(libxl__gc *gc, void *ptr)
+void libxl__ptr_add(libxl__gc *gc, void *ptr)
{
int i;
- void **re;
if (!ptr)
- return 0;
+ return;
/* fast case: we have space in the array for storing the pointer */
for (i = 0; i < gc->alloc_maxsize; i++) {
if (!gc->alloc_ptrs[i]) {
gc->alloc_ptrs[i] = ptr;
- return 0;
+ return;
}
}
- /* realloc alloc_ptrs manually with calloc/free/replace */
- re = calloc(gc->alloc_maxsize + 25, sizeof(void *));
- if (!re)
- return -1;
- for (i = 0; i < gc->alloc_maxsize; i++)
- re[i] = gc->alloc_ptrs[i];
- /* assign the next pointer */
- re[i] = ptr;
+ int new_maxsize = gc->alloc_maxsize * 2 + 25;
+ assert(new_maxsize < INT_MAX / sizeof(void*) / 2);
+ gc->alloc_ptrs = realloc(gc->alloc_ptrs, new_maxsize * sizeof(void *));
+ if (!gc->alloc_ptrs)
+ libxl__alloc_failed(CTX, __func__, sizeof(void*), new_maxsize);
- /* replace the old alloc_ptr */
- free(gc->alloc_ptrs);
- gc->alloc_ptrs = re;
- gc->alloc_maxsize += 25;
- return 0;
+ gc->alloc_ptrs[gc->alloc_maxsize++] = ptr;
+
+ while (gc->alloc_maxsize < new_maxsize)
+ gc->alloc_ptrs[gc->alloc_maxsize++] = 0;
+
+ return;
}
void libxl__free_all(libxl__gc *gc)
@@ -71,10 +76,7 @@ void libxl__free_all(libxl__gc *gc)
void *libxl__zalloc(libxl__gc *gc, int bytes)
{
void *ptr = calloc(bytes, 1);
- if (!ptr) {
- libxl__error_set(gc, ENOMEM);
- return NULL;
- }
+ if (!ptr) libxl__alloc_failed(CTX, __func__, bytes, 1);
libxl__ptr_add(gc, ptr);
return ptr;
@@ -83,10 +85,7 @@ void *libxl__zalloc(libxl__gc *gc, int bytes)
void *libxl__calloc(libxl__gc *gc, size_t nmemb, size_t size)
{
void *ptr = calloc(nmemb, size);
- if (!ptr) {
- libxl__error_set(gc, ENOMEM);
- return NULL;
- }
+ if (!ptr) libxl__alloc_failed(CTX, __func__, nmemb, size);
libxl__ptr_add(gc, ptr);
return ptr;
@@ -97,9 +96,8 @@ void *libxl__realloc(libxl__gc *gc, void *ptr, size_t new_size)
void *new_ptr = realloc(ptr, new_size);
int i = 0;
- if (new_ptr == NULL && new_size != 0) {
- return NULL;
- }
+ if (new_ptr == NULL && new_size != 0)
+ libxl__alloc_failed(CTX, __func__, new_size, 1);
if (ptr == NULL) {
libxl__ptr_add(gc, new_ptr);
@@ -112,7 +110,6 @@ void *libxl__realloc(libxl__gc *gc, void *ptr, size_t new_size)
}
}
-
return new_ptr;
}
@@ -126,16 +123,13 @@ char *libxl__sprintf(libxl__gc *gc, const char *fmt, ...)
ret = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
- if (ret < 0) {
- return NULL;
- }
+ assert(ret >= 0);
s = libxl__zalloc(gc, ret + 1);
- if (s) {
- va_start(ap, fmt);
- ret = vsnprintf(s, ret + 1, fmt, ap);
- va_end(ap);
- }
+ va_start(ap, fmt);
+ ret = vsnprintf(s, ret + 1, fmt, ap);
+ va_end(ap);
+
return s;
}
@@ -143,8 +137,9 @@ char *libxl__strdup(libxl__gc *gc, const char *c)
{
char *s = strdup(c);
- if (s)
- libxl__ptr_add(gc, s);
+ if (!s) libxl__alloc_failed(CTX, __func__, strlen(c), 1);
+
+ libxl__ptr_add(gc, s);
return s;
}
@@ -153,8 +148,7 @@ char *libxl__strndup(libxl__gc *gc, const char *c, size_t n)
{
char *s = strndup(c, n);
- if (s)
- libxl__ptr_add(gc, s);
+ if (!s) libxl__alloc_failed(CTX, __func__, n, 1);
return s;
}
@@ -175,6 +169,9 @@ void libxl__logv(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval,
const char *file, int line, const char *func,
const char *fmt, va_list ap)
{
+ /* WARNING this function may not call any libxl-provided
+ * memory allocation function, as those may
+ * call libxl__alloc_failed which calls libxl__logv. */
char *enomem = "[out of memory formatting log message]";
char *base = NULL;
int rc, esave;
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 04f13f6..2ad446a 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -116,6 +116,12 @@ typedef struct libxl__gc libxl__gc;
typedef struct libxl__egc libxl__egc;
typedef struct libxl__ao libxl__ao;
+void libxl__alloc_failed(libxl_ctx *, const char *func,
+ size_t nmemb, size_t size) __attribute__((noreturn));
+ /* func, size and nmemb are used only in the log message.
+ * You may pass size==0 if size and nmemb are not meaningful
+ * and should not be printed. */
+
typedef struct libxl__ev_fd libxl__ev_fd;
typedef void libxl__ev_fd_callback(libxl__egc *egc, libxl__ev_fd *ev,
int fd, short events, short revents);
@@ -380,7 +386,7 @@ static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc)
* collection on exit from the outermost libxl callframe.
*/
/* register @ptr in @gc for free on exit from outermost libxl callframe. */
-_hidden int libxl__ptr_add(libxl__gc *gc, void *ptr);
+_hidden void libxl__ptr_add(libxl__gc *gc, void *ptr);
/* if this is the outermost libxl callframe then free all pointers in @gc */
_hidden void libxl__free_all(libxl__gc *gc);
/* allocate and zero @bytes. (similar to a gc'd malloc(3)+memzero()) */
--
1.7.2.5
next prev parent reply other threads:[~2012-04-10 19:07 UTC|newest]
Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-10 19:07 [PATCH v4 00/31] libxl child process handling Ian Jackson
2012-04-10 19:07 ` [PATCH 01/31] .gitignore: Add a missing file Ian Jackson
2012-04-11 8:44 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 02/31] libxl: ao: allow immediate completion Ian Jackson
2012-04-10 19:07 ` [PATCH 03/31] libxl: fix hang due to libxl__initiate_device_remove Ian Jackson
2012-04-10 19:07 ` [PATCH 04/31] libxl: Fix eventloop_iteration over-locking Ian Jackson
2012-04-10 19:07 ` [PATCH 05/31] libxl: remove poller from list in libxl__poller_get Ian Jackson
2012-04-10 19:07 ` [PATCH 06/31] libxl: Fix leak of ctx->lock Ian Jackson
2012-04-10 19:07 ` [PATCH 07/31] tools: Correct PTHREAD options in config/StdGNU.mk Ian Jackson
2012-04-10 19:07 ` [PATCH 08/31] libxl: Use PTHREAD_CFLAGS, LDFLAGS, LIBS Ian Jackson
2012-04-10 19:07 ` [PATCH 09/31] tools: Use PTHREAD_CFLAGS, _LDFLAGS, _LIBS Ian Jackson
2012-04-10 19:07 ` Ian Jackson [this message]
2012-04-11 9:02 ` [PATCH 10/31] libxl: Crash (more sensibly) on malloc failure Ian Campbell
2012-04-11 10:24 ` Ian Jackson
2012-04-11 10:47 ` Ian Campbell
2012-04-11 11:04 ` Ian Jackson
2012-04-11 11:14 ` Ian Campbell
2012-04-11 11:21 ` Ian Jackson
2012-04-11 11:23 ` Ian Jackson
2012-04-11 11:33 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 11/31] libxl: Make libxl__zalloc et al tolerate a NULL gc Ian Jackson
2012-04-10 19:07 ` [PATCH 12/31] libxl: Introduce some convenience macros Ian Jackson
2012-04-10 19:07 ` [PATCH 13/31] libxl: include <ctype.h> and introduce CTYPE helper macro Ian Jackson
2012-04-10 19:07 ` [PATCH 14/31] libxl: Provide libxl_string_list_length Ian Jackson
2012-04-10 19:07 ` [PATCH 15/31] libxl: include <_libxl_paths.h> in libxl_internal.h Ian Jackson
2012-04-10 19:07 ` [PATCH 16/31] libxl: abolish libxl_ctx_postfork Ian Jackson
2012-04-10 19:07 ` [PATCH 17/31] libxl: libxl_event.c:beforepoll_internal, REQUIRE_FDS Ian Jackson
2012-04-10 19:07 ` [PATCH 18/31] libxl: Protect fds with CLOEXEC even with forking threads Ian Jackson
2012-04-11 9:14 ` Ian Campbell
2012-04-11 10:38 ` Ian Jackson
2012-04-10 19:07 ` [PATCH 19/31] libxl: provide STATE_AO_GC Ian Jackson
2012-04-11 9:17 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 20/31] libxl: handle POLLERR, POLLHUP, POLLNVAL properly Ian Jackson
2012-04-11 9:21 ` Ian Campbell
2012-04-11 10:50 ` Ian Jackson
2012-04-11 10:52 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 21/31] libxl: support multiple libxl__ev_fds for the same fd Ian Jackson
2012-04-10 19:07 ` [PATCH 22/31] libxl: event API: new facilities for waiting for subprocesses Ian Jackson
2012-04-11 9:42 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 23/31] autoconf: New test for openpty et al Ian Jackson
2012-04-10 19:07 ` [PATCH 24/31] libxl: provide libxl__remove_file " Ian Jackson
2012-04-11 9:54 ` Ian Campbell
2012-04-11 10:56 ` Ian Jackson
2012-04-11 11:03 ` Ian Campbell
2012-04-10 19:07 ` [PATCH 25/31] libxl: Introduce libxl__sendmsg_fds and libxl__recvmsg_fds Ian Jackson
2012-04-10 19:08 ` [PATCH 26/31] libxl: Clean up setdefault in do_domain_create Ian Jackson
2012-04-11 9:57 ` Ian Campbell
2012-04-10 19:08 ` [PATCH 27/31] libxl: provide libxl__datacopier_* Ian Jackson
2012-04-11 10:47 ` Ian Campbell
2012-04-11 11:11 ` Ian Jackson
2012-04-10 19:08 ` [PATCH 28/31] libxl: provide libxl__openpty_* Ian Jackson
2012-04-11 11:03 ` Ian Campbell
2012-04-11 11:19 ` Ian Jackson
2012-04-11 11:33 ` Ian Campbell
2012-04-10 19:08 ` [PATCH 29/31] libxl: ao: Convert libxl_run_bootloader Ian Jackson
2012-04-11 11:31 ` Ian Campbell
2012-04-11 11:39 ` Ian Jackson
2012-04-11 11:45 ` Ian Campbell
2012-04-10 19:08 ` [PATCH 30/31] libxl: make libxl_create_logfile const-correct Ian Jackson
2012-04-11 9:58 ` Ian Campbell
2012-04-10 19:08 ` [PATCH 31/31] libxl: log bootloader output Ian Jackson
2012-04-11 10:00 ` Ian Campbell
2012-04-11 9:04 ` [PATCH v4 00/31] libxl child process handling Ian Campbell
2012-04-11 10:35 ` Ian Jackson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1334084885-14474-11-git-send-email-ian.jackson@eu.citrix.com \
--to=ian.jackson@eu.citrix.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).