[asterisk-commits] tilghman: branch tilghman/malloc_hold r208743 - in /team/tilghman/malloc_hold...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jul 24 17:35:46 CDT 2009
Author: tilghman
Date: Fri Jul 24 17:35:43 2009
New Revision: 208743
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=208743
Log:
Save what I have, for a memory error detection that detects both bad writes AND bad reads.
Modified:
team/tilghman/malloc_hold/configure
team/tilghman/malloc_hold/include/asterisk/autoconfig.h.in
team/tilghman/malloc_hold/main/astmm.c
Modified: team/tilghman/malloc_hold/include/asterisk/autoconfig.h.in
URL: http://svn.asterisk.org/svn-view/asterisk/team/tilghman/malloc_hold/include/asterisk/autoconfig.h.in?view=diff&rev=208743&r1=208742&r2=208743
==============================================================================
--- team/tilghman/malloc_hold/include/asterisk/autoconfig.h.in (original)
+++ team/tilghman/malloc_hold/include/asterisk/autoconfig.h.in Fri Jul 24 17:35:43 2009
@@ -594,6 +594,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* Define to 1 if the C compiler supports function prototypes. */
+#undef PROTOTYPES
+
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
@@ -609,6 +612,11 @@
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
+
+/* Define to 1 if the `setvbuf' function takes the buffering type as its
+ second argument and the buffer pointer as the third, as on System V before
+ release 3. */
+#undef SETVBUF_REVERSED
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
@@ -630,46 +638,50 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
-/* Enable extensions on AIX 3, Interix. */
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
-/* Enable threading extensions on Solaris. */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
-/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#undef _FILE_OFFSET_BITS
-
-/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
-#undef _LARGEFILE_SOURCE
-
-/* Define for large files, on AIX-style hosts. */
-#undef _LARGE_FILES
-
-/* Define to 1 if on MINIX. */
-#undef _MINIX
-
-/* Define to 2 if the system does not provide POSIX.1 features except with
- this defined. */
-#undef _POSIX_1_SOURCE
-
-/* Define to 1 if you need to in order for `stat' and other things to work. */
-#undef _POSIX_SOURCE
+
+/* Define like PROTOTYPES; this can be used by system headers. */
+#undef __PROTOTYPES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
Modified: team/tilghman/malloc_hold/main/astmm.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/tilghman/malloc_hold/main/astmm.c?view=diff&rev=208743&r1=208742&r2=208743
==============================================================================
--- team/tilghman/malloc_hold/main/astmm.c (original)
+++ team/tilghman/malloc_hold/main/astmm.c Fri Jul 24 17:35:43 2009
@@ -33,6 +33,11 @@
#include <string.h>
#include <stddef.h>
#include <time.h>
+#include <sys/mman.h>
+#include <signal.h>
+#ifdef MALLOC_HOLD
+#include <malloc.h>
+#endif /* MALLOC_HOLD */
#include "asterisk/cli.h"
#include "asterisk/logger.h"
@@ -45,6 +50,26 @@
#endif
#define SOME_PRIME 563
+
+/* Cannot include utils.h, as it defines things that this file implements,
+ * but could eventually put these defines in a separate header file. */
+int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
+ void *data, size_t stacksize, const char *file, const char *caller,
+ int line, const char *start_fn);
+#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024)
+
+#if defined(LOW_MEMORY)
+#define AST_BACKGROUND_STACKSIZE (((sizeof(void *) * 8 * 2) - 16) * 1024)
+#else
+#define AST_BACKGROUND_STACKSIZE AST_STACKSIZE
+#endif
+
+#define ast_pthread_create_background(a, b, c, d) ast_pthread_create_stack(a, b, c, d, \
+ AST_BACKGROUND_STACKSIZE, \
+ __FILE__, __FUNCTION__, \
+ __LINE__, #c)
+#endif
+#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
enum func_type {
FUNC_CALLOC = 1,
@@ -70,6 +95,19 @@
#define FENCE_MAGIC 0xdeadbeef
static FILE *mmlog;
+
+#ifdef MALLOC_HOLD
+static ssize_t pagesize = -1;
+static struct sigaction default_sigsegv;
+#endif
+
+static struct violations {
+ void *base_addr;
+ void *violation;
+ int error;
+ time_t when;
+} violations[100] = { { NULL, } };
+static int last_violation = -1;
/* NOTE: Be EXTREMELY careful with modifying this structure; the total size of this structure
must result in 'automatic' alignment so that the 'fence' field lands exactly at the end of
@@ -85,12 +123,20 @@
static struct ast_region {
struct ast_region *next;
+ size_t len;
+ size_t fullsize;
+#ifdef MALLOC_HOLD
+ char free_file[40];
+ char free_func[40];
+ unsigned int free_lineno;
unsigned int freetime;
- unsigned int unused;
- size_t len;
- char file[40];
- char func[40];
- unsigned int lineno;
+ int mperm;
+ int violation;
+ void *vlocation;
+#endif
+ char alloc_file[40];
+ char alloc_func[40];
+ unsigned int alloc_lineno;
enum func_type which;
unsigned int cache; /* region was allocated as part of a cache pool */
unsigned int fence;
@@ -121,16 +167,37 @@
void *ptr = NULL;
unsigned int *fence;
int hash;
-
+#ifdef MALLOC_HOLD
+ size_t fullsize = size + sizeof(*reg) + sizeof(*fence);
+
+ if (pagesize == -1 && (pagesize = sysconf(_SC_PAGESIZE)) == -1) {
+ ast_log(LOG_ERROR, "Cannot retrieve system memory page size?");
+ abort();
+ }
+
+ /*!
+ * What, expand the size to cover the full page? Doesn't that eat memory?
+ * Yes, but consider that we aren't the only consumers of memory in this
+ * process. Supposing we only allocated half a page. Malloc would be free
+ * to allocate the remaining space to something else, like perhaps a libc
+ * internal structure. If we then protect that memory, and libc tries to
+ * access it, we flag a memory error where none existed. Thus, we must
+ * only allocate full memory pages.
+ */
+ fullsize = (fullsize / pagesize) * pagesize == fullsize ? fullsize : ((fullsize / pagesize) + 1) * pagesize;
+ if (!(reg = memalign(pagesize, fullsize))) {
+#else /* !MALLOC_HOLD */
if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) {
+#endif
astmm_log("Memory Allocation Failure - '%d' bytes in function %s "
"at line %d of %s\n", (int) size, func, lineno, file);
}
- ast_copy_string(reg->file, file, sizeof(reg->file));
- ast_copy_string(reg->func, func, sizeof(reg->func));
- reg->lineno = lineno;
+ ast_copy_string(reg->alloc_file, file, sizeof(reg->alloc_file));
+ ast_copy_string(reg->alloc_func, func, sizeof(reg->alloc_func));
+ reg->alloc_lineno = lineno;
reg->len = size;
+ reg->fullsize = fullsize;
reg->which = which;
reg->cache = cache;
ptr = reg->data;
@@ -165,7 +232,8 @@
return len;
}
-static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
+void __ast_free_region(void *ptr, const char *file, int lineno, const char *func);
+void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
{
int hash;
struct ast_region *reg, *prev = NULL;
@@ -190,23 +258,34 @@
fence = (unsigned int *)(reg->data + reg->len);
if (reg->fence != FENCE_MAGIC) {
astmm_log("WARNING: Low fence violation at %p, in %s of %s, "
- "line %d\n", reg->data, reg->func, reg->file, reg->lineno);
+ "line %d, freed in %s of %s, line %d\n", reg->data,
+ reg->alloc_func, reg->alloc_file, reg->alloc_lineno,
+ reg->free_func, reg->free_file, reg->free_lineno);
+ /* Restore FENCE_MAGIC, as it's needed for extended checking */
+ reg->fence = FENCE_MAGIC;
}
if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
astmm_log("WARNING: High fence violation at %p, in %s of %s, "
- "line %d\n", reg->data, reg->func, reg->file, reg->lineno);
- }
-
- memset(ptr, 0, reg->len);
- reg->freetime = now;
-
- /* Move to "free" list */
+ "line %d, freed in %s of %s, line %d\n", reg->data,
+ reg->alloc_func, reg->alloc_file, reg->alloc_lineno,
+ reg->free_func, reg->free_file, reg->free_lineno);
+ }
+
+ /* Remove from "allocated" list */
if (prev) {
prev->next = reg->next;
} else {
regions[hash] = reg->next;
}
reg->next = NULL;
+
+ reg->mperm = PROT_NONE;
+ reg->violation = 0;
+ reg->vlocation = NULL;
+ reg->freetime = now;
+ ast_copy_string(reg->free_file, file, sizeof(reg->free_file));
+ ast_copy_string(reg->free_func, func, sizeof(reg->free_func));
+ reg->free_lineno = lineno;
/* By inserting at the end of the list, we ensure that we won't need
* to search the list for entries to delete, but merely prune the
@@ -216,9 +295,12 @@
lastfree = reg;
regions[SOME_PRIME] = reg;
} else {
+ mprotect(lastfree, sizeof(*lastfree), PROT_READ | PROT_WRITE);
lastfree->next = reg;
+ mprotect(lastfree, sizeof(*lastfree), PROT_NONE);
lastfree = reg;
}
+ mprotect(reg, reg->fullsize, PROT_NONE);
break;
}
prev = reg;
@@ -247,11 +329,11 @@
fence = (unsigned int *)(reg->data + reg->len);
if (reg->fence != FENCE_MAGIC) {
astmm_log("WARNING: Low fence violation at %p, in %s of %s, "
- "line %d\n", reg->data, reg->func, reg->file, reg->lineno);
+ "line %d\n", reg->data, reg->alloc_func, reg->alloc_file, reg->alloc_lineno);
}
if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
astmm_log("WARNING: High fence violation at %p, in %s of %s, "
- "line %d\n", reg->data, reg->func, reg->file, reg->lineno);
+ "line %d\n", reg->data, reg->alloc_func, reg->alloc_file, reg->alloc_lineno);
}
free(reg);
} else {
@@ -403,22 +485,22 @@
ast_mutex_lock(®lock);
for (x = 0; x < SOME_PRIME; x++) {
for (reg = regions[x]; reg; reg = reg->next) {
- if (!fn || !strcasecmp(fn, reg->file) || !strcasecmp(fn, "anomolies")) {
+ if (!fn || !strcasecmp(fn, reg->alloc_file) || !strcasecmp(fn, "anomolies")) {
fence = (unsigned int *)(reg->data + reg->len);
if (reg->fence != FENCE_MAGIC) {
astmm_log("WARNING: Low fence violation at %p, "
"in %s of %s, line %d\n", reg->data,
- reg->func, reg->file, reg->lineno);
+ reg->alloc_func, reg->alloc_file, reg->alloc_lineno);
}
if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
astmm_log("WARNING: High fence violation at %p, in %s of %s, "
- "line %d\n", reg->data, reg->func, reg->file, reg->lineno);
+ "line %d\n", reg->data, reg->alloc_func, reg->alloc_file, reg->alloc_lineno);
}
}
- if (!fn || !strcasecmp(fn, reg->file)) {
+ if (!fn || !strcasecmp(fn, reg->alloc_file)) {
ast_cli(fd, "%10d bytes allocated%s in %20s at line %5d of %s\n",
(int) reg->len, reg->cache ? " (cache)" : "",
- reg->func, reg->lineno, reg->file);
+ reg->alloc_func, reg->alloc_lineno, reg->alloc_file);
len += reg->len;
if (reg->cache)
cache_len += reg->len;
@@ -458,17 +540,17 @@
ast_mutex_lock(®lock);
for (x = 0; x < SOME_PRIME; x++) {
for (reg = regions[x]; reg; reg = reg->next) {
- if (fn && strcasecmp(fn, reg->file))
+ if (fn && strcasecmp(fn, reg->alloc_file))
continue;
for (cur = list; cur; cur = cur->next) {
- if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
+ if ((!fn && !strcmp(cur->fn, reg->alloc_file)) || (fn && !strcmp(cur->fn, reg->alloc_func)))
break;
}
if (!cur) {
cur = alloca(sizeof(*cur));
memset(cur, 0, sizeof(*cur));
- ast_copy_string(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn));
+ ast_copy_string(cur->fn, fn ? reg->alloc_func : reg->alloc_file, sizeof(cur->fn));
cur->next = list;
list = cur;
}
@@ -547,35 +629,74 @@
static void *memory_destructor(void *notused)
{
struct ast_region *cur;
+ int last_seen_violation = -1;
for (;;) {
+ /* Any errors to report? */
+ if (last_seen_violation != last_violation) {
+ for (last_seen_violation++; last_seen_violation != last_violation;
+ last_seen_violation = (last_seen_violation == ARRAY_LEN(violations) - 1) ? 0 : last_seen_violation + 1) {
+ if ((cur = violations[last_seen_violation].base_addr) == NULL) {
+ memset(&violations[last_seen_violation], 0, sizeof(violations[0]));
+ continue;
+ }
+ astmm_log("Intercepted invalid %s to %p (%p+%d), originally allocated in %s at %s:%d and freed in %s at %s:%d\n",
+ violations[last_seen_violation].error == PROT_READ ? "read" : "write",
+ violations[last_seen_violation].violation, cur->data,
+ violations[last_seen_violation].violation - (void *) cur->data,
+ cur->alloc_func, cur->alloc_file, cur->alloc_lineno,
+ cur->free_func, cur->free_file, cur->free_lineno);
+ memset(&violations[last_seen_violation], 0, sizeof(violations[0]));
+ cur->violation = 0;
+ cur->mperm = PROT_NONE;
+ mprotect(cur, cur->fullsize, PROT_NONE);
+ }
+ last_seen_violation--;
+ }
ast_mutex_lock(®lock);
/* Delete any segment which is free for at least 120 seconds */
- while ((cur = regions[SOME_PRIME]) && cur->freetime < time(NULL) - 120) {
- unsigned char *ptr;
-
- for (ptr = cur->data; ptr < cur->data + cur->len; ptr++) {
- if (*ptr != 0) {
- astmm_log("WARNING: memory (%p) written to after being freed "
- "at %p (+%d/%d), (originally in %s of %s, line %d)\n",
- cur->data, ptr, ptr - cur->data, cur->len, cur->func, cur->file, cur->lineno);
- break;
- }
- }
-
+ while ((cur = regions[SOME_PRIME]) && !mprotect(cur, sizeof(*cur), PROT_READ) && cur->freetime < time(NULL) - 120) {
+ int i;
+
+ if (mprotect(cur, cur->fullsize, PROT_READ)) {
+ astmm_log("ERROR: cannot access freed memory at %p, (originally in %s of %s, line %d, freed in %s of %s, line %d)\n",
+ cur->data, cur->alloc_func, cur->alloc_file, cur->alloc_lineno, cur->free_func, cur->free_file, cur->free_lineno);
+ /* XXX crash, perhaps? XXX (should not ever happen) */
+ }
+
+ cur->mperm = PROT_READ;
regions[SOME_PRIME] = cur->next;
if (cur == lastfree) {
- astmm_log("Freeing last bit of memory in free list.\n");
lastfree = NULL;
}
#if 0 /* Verification that this thread is running only */
- astmm_log("Freeing memory at %p (size %d, originally allocated in %s of %s, line %d)\n", cur->data, cur->len, cur->func, cur->file, cur->lineno);
-#endif
+ astmm_log("Freeing memory at %p (size %d, originally allocated in %s of %s, line %d)\n", cur->data, cur->len, cur->alloc_func, cur->alloc_file, cur->alloc_lineno);
+#endif
+ if (cur->violation) {
+ for (i = 0; i < ARRAY_LEN(violations); i++) {
+ if (cur == violations[i].base_addr) {
+ astmm_log("Intercepted invalid %s to %p (%p+%d), originally allocated in %s at %s:%d and freed in %s at %s:%d\n",
+ violations[last_seen_violation].error == PROT_READ ? "read" : "write",
+ violations[last_seen_violation].violation, cur->data,
+ violations[last_seen_violation].violation - (void *) cur->data,
+ cur->alloc_func, cur->alloc_file, cur->alloc_lineno,
+ cur->free_func, cur->free_file, cur->free_lineno);
+ memset(&violations[i], 0, sizeof(violations[i]));
+ break;
+ }
+ }
+ }
free(cur);
}
- ast_mutex_unlock(®lock);
- if (regions[SOME_PRIME]) {
- sleep(120 - (time(NULL) - regions[SOME_PRIME]->freetime));
+ if ((cur = regions[SOME_PRIME])) {
+ int sleep_time = 120 - (time(NULL) - cur->freetime);
+
+ /* Re-protect region opened to reads while we examined cur->freetime */
+ mprotect(cur, sizeof(*cur), PROT_NONE);
+
+ ast_mutex_unlock(®lock);
+ sleep(sleep_time);
} else {
+ ast_mutex_unlock(®lock);
astmm_log("Nothing in free list. Sleeping for 120 seconds.\n");
sleep(120);
}
@@ -584,24 +705,113 @@
return NULL;
}
-/* Cannot include utils.h, as it defines things that this file implements,
- * but could eventually put these defines in a separate header file. */
-int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
- void *data, size_t stacksize, const char *file, const char *caller,
- int line, const char *start_fn);
-#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024)
-
-#if defined(LOW_MEMORY)
-#define AST_BACKGROUND_STACKSIZE (((sizeof(void *) * 8 * 2) - 16) * 1024)
-#else
-#define AST_BACKGROUND_STACKSIZE AST_STACKSIZE
-#endif
-
-#define ast_pthread_create_background(a, b, c, d) ast_pthread_create_stack(a, b, c, d, \
- AST_BACKGROUND_STACKSIZE, \
- __FILE__, __FUNCTION__, \
- __LINE__, #c)
-#endif
+static void handle_sigsegv(int signal, siginfo_t *info, void *unused)
+{
+ struct ast_region *cur;
+
+ if (signal != SIGSEGV) {
+ return;
+ }
+
+ /* Access violation errors are the only things I handle;
+ * anything else goes to the default handler. */
+ if (info->si_code != SEGV_ACCERR || info->si_addr == NULL) {
+ if (default_sigsegv.sa_flags & SA_SIGINFO && default_sigsegv.sa_sigaction != NULL) {
+ (default_sigsegv.sa_sigaction)(signal, info, unused);
+ } else if (default_sigsegv.sa_handler != NULL) {
+ (default_sigsegv.sa_handler)(signal);
+ } else {
+ abort();
+ }
+ return;
+ }
+
+ /* Find base address */
+ cur = (void *) ((size_t) info->si_addr / pagesize * pagesize);
+ mprotect(cur, sizeof(*cur), PROT_READ);
+ while (cur->fence != FENCE_MAGIC && cur->len > cur->fullsize) {
+ /*!
+ * This loop is kind of weird. By calling this routine, we expect that
+ * the memory segment is one allocated by us, so this should terminate
+ * when we find FENCE_MAGIC. OTOH, it's possible that this wasn't us,
+ * and we'll eventually step on something that wasn't an access problem,
+ * the signal handler will fire again, call the default handler, and we'll
+ * crash. That is what we'd expect to happen, anyway, if this wasn't our
+ * segment, so all is good.
+ */
+ cur -= pagesize;
+ mprotect(cur, sizeof(*cur), PROT_READ);
+ }
+
+ /*!
+ * The general rule of thumb is don't try to allocate memory or output to a
+ * file descriptor in a signal handler. Therefore, we must otherwise raise
+ * flags for later reporting. This might not be completely true, but
+ * consider what signal handler this is. This isn't the place to split
+ * hairs.
+ */
+ if (cur->mperm == PROT_READ) {
+ int newperm = PROT_READ | PROT_WRITE | PROT_EXEC;
+ mprotect(cur, cur->fullsize, newperm);
+ cur->mperm = newperm;
+ if (cur->vlocation == info->si_addr) {
+ cur->violation = PROT_WRITE;
+ if (violations[last_violation].base_addr == cur) {
+ violations[last_violation].error = PROT_WRITE;
+ }
+ }
+ } else {
+ /* We're about to modify, so let us write */
+ mprotect(cur, cur->fullsize, PROT_READ | PROT_WRITE);
+ cur->mperm = PROT_READ;
+ cur->vlocation = info->si_addr;
+ cur->violation = PROT_READ;
+ mprotect(cur, cur->fullsize, cur->mperm);
+
+ if (++last_violation > ARRAY_LEN(violations)) {
+ last_violation = 0;
+ }
+ violations[last_violation].base_addr = cur;
+ violations[last_violation].violation = info->si_addr;
+ violations[last_violation].when = time(NULL);
+ violations[last_violation].error = cur->violation;
+ }
+
+ /*!
+ * Okay, if we've done our job right, we now know that the user
+ * stepped on memory that was freed, we've intercepted that access,
+ * allowed the memory to be read/written, and return. This will allow
+ * the (previously illegal) operation to continue, as if the segfault
+ * never actually occurred. Yes, that seems weird, but that's the way
+ * this signal works.
+ *
+ * Now here's the interesting part. This signal handler will get
+ * re-entered immediately if we didn't clear the right protection, which
+ * is what we designed, when we differentiate between an attempted read
+ * (which won't come back) and a write (which will). We can therefore
+ * determine which type of access occurred to free'd memory.
+ *
+ * The rub is that once we unprotect this memory, we cannot easily
+ * re-protect the memory, since returning releases the control from the
+ * signal handler. Thus, we only will detect the FIRST illegal access
+ * of (this segment of) free'd memory, not any subsequent. This hopefully
+ * is sufficient for our purposes.
+ */
+}
+
+static void mm_cleanup(void)
+{
+ struct ast_region *reg;
+ ast_mutex_lock(®lock);
+ while ((reg = regions[SOME_PRIME])) {
+ mprotect(reg, sizeof(*reg), PROT_READ | PROT_WRITE);
+ mprotect(reg, reg->fullsize, PROT_READ | PROT_WRITE);
+ reg->violation = 0;
+ regions[SOME_PRIME] = reg->next;
+ free(reg);
+ }
+ ast_mutex_unlock(®lock);
+}
void __ast_mm_init(void)
{
@@ -609,6 +819,21 @@
size_t pad = sizeof(struct ast_region) - offsetof(struct ast_region, data);
#ifdef MALLOC_HOLD
pthread_t notused;
+ struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_NODEFER, .sa_sigaction = handle_sigsegv, };
+
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGSEGV, &sa, &default_sigsegv) == -1) {
+ ast_log(LOG_ERROR, "Cannot handle segmentation faults?");
+ abort();
+ }
+
+ if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) {
+ ast_log(LOG_ERROR, "Cannot retrieve system memory page size?");
+ abort();
+ }
+
+ /* Remove all memory protections before we exit */
+ ast_register_atexit(mm_cleanup);
ast_pthread_create_background(¬used, NULL, memory_destructor, NULL);
#endif
More information about the asterisk-commits
mailing list