diff options
Diffstat (limited to 'bdb/os/os_alloc.c')
-rw-r--r-- | bdb/os/os_alloc.c | 308 |
1 files changed, 212 insertions, 96 deletions
diff --git a/bdb/os/os_alloc.c b/bdb/os/os_alloc.c index ee4a0f3c91f..5b38cc7d6f1 100644 --- a/bdb/os/os_alloc.c +++ b/bdb/os/os_alloc.c @@ -1,14 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1997, 1998, 1999, 2000 + * Copyright (c) 1997-2002 * Sleepycat Software. All rights reserved. */ #include "db_config.h" #ifndef lint -static const char revid[] = "$Id: os_alloc.c,v 11.18 2000/11/30 00:58:42 ubell Exp $"; +static const char revid[] = "$Id: os_alloc.c,v 11.32 2002/08/06 04:57:07 bostic Exp $"; #endif /* not lint */ #ifndef NO_SYSTEM_INCLUDES @@ -19,10 +19,14 @@ static const char revid[] = "$Id: os_alloc.c,v 11.18 2000/11/30 00:58:42 ubell E #endif #include "db_int.h" -#include "os_jump.h" #ifdef DIAGNOSTIC -static void __os_guard __P((void)); +static void __os_guard __P((DB_ENV *)); + +union __db_alloc { + size_t size; + double align; +}; #endif /* @@ -37,12 +41,150 @@ static void __os_guard __P((void)); * !!! * Correct for systems that don't set errno when malloc and friends fail. * + * !!! + * There is no circumstance in which we can call __os_umalloc, __os_urealloc + * or __os_ufree without an environment handle, as we need one to determine + * whether or not to use an application-specified malloc function. If we + * don't have an environment handle, we should be calling __os_XXX instead. + * Make DIAGNOSTIC blow up if we get this wrong. + * * Out of memory. * We wish to hold the whole sky, * But we never will. */ /* + * __os_umalloc -- + * A malloc(3) function that will use, in order of preference, + * the allocation function specified to the DB handle, the DB_ENV + * handle, or __os_malloc. + * + * PUBLIC: int __os_umalloc __P((DB_ENV *, size_t, void *)); + */ +int +__os_umalloc(dbenv, size, storep) + DB_ENV *dbenv; + size_t size; + void *storep; +{ + int ret; + + /* Require an environment handle. */ + DB_ASSERT(dbenv != NULL); + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + + if (dbenv == NULL || dbenv->db_malloc == NULL) { + if (DB_GLOBAL(j_malloc) != NULL) + *(void **)storep = DB_GLOBAL(j_malloc)(size); + else + *(void **)storep = malloc(size); + if (*(void **)storep == NULL) { + /* + * Correct error return, see __os_malloc. + */ + if ((ret = __os_get_errno()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(dbenv, + "malloc: %s: %lu", strerror(ret), (u_long)size); + return (ret); + } + return (0); + } + + if ((*(void **)storep = dbenv->db_malloc(size)) == NULL) { + __db_err(dbenv, "User-specified malloc function returned NULL"); + return (ENOMEM); + } + + return (0); +} + +/* + * __os_urealloc -- + * realloc(3) counterpart to __os_umalloc. + * + * PUBLIC: int __os_urealloc __P((DB_ENV *, size_t, void *)); + */ +int +__os_urealloc(dbenv, size, storep) + DB_ENV *dbenv; + size_t size; + void *storep; +{ + int ret; + void *ptr; + + ptr = *(void **)storep; + + /* Require an environment handle. */ + DB_ASSERT(dbenv != NULL); + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + + if (dbenv == NULL || dbenv->db_realloc == NULL) { + if (ptr == NULL) + return (__os_umalloc(dbenv, size, storep)); + + if (DB_GLOBAL(j_realloc) != NULL) + *(void **)storep = DB_GLOBAL(j_realloc)(ptr, size); + else + *(void **)storep = realloc(ptr, size); + if (*(void **)storep == NULL) { + /* + * Correct errno, see __os_realloc. + */ + if ((ret = __os_get_errno()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(dbenv, + "realloc: %s: %lu", strerror(ret), (u_long)size); + return (ret); + } + return (0); + } + + if ((*(void **)storep = dbenv->db_realloc(ptr, size)) == NULL) { + __db_err(dbenv, + "User-specified realloc function returned NULL"); + return (ENOMEM); + } + + return (0); +} + +/* + * __os_ufree -- + * free(3) counterpart to __os_umalloc. + * + * PUBLIC: int __os_ufree __P((DB_ENV *, void *)); + */ +int +__os_ufree(dbenv, ptr) + DB_ENV *dbenv; + void *ptr; +{ + /* Require an environment handle. */ + DB_ASSERT(dbenv != NULL); + + if (dbenv != NULL && dbenv->db_free != NULL) + dbenv->db_free(ptr); + else if (DB_GLOBAL(j_free) != NULL) + DB_GLOBAL(j_free)(ptr); + else + free(ptr); + + return (0); +} + +/* * __os_strdup -- * The strdup(3) function for DB. * @@ -61,7 +203,7 @@ __os_strdup(dbenv, str, storep) *(void **)storep = NULL; size = strlen(str) + 1; - if ((ret = __os_malloc(dbenv, size, NULL, &p)) != 0) + if ((ret = __os_malloc(dbenv, size, &p)) != 0) return (ret); memcpy(p, str, size); @@ -86,7 +228,7 @@ __os_calloc(dbenv, num, size, storep) int ret; size *= num; - if ((ret = __os_malloc(dbenv, size, NULL, &p)) != 0) + if ((ret = __os_malloc(dbenv, size, &p)) != 0) return (ret); memset(p, 0, size); @@ -99,13 +241,13 @@ __os_calloc(dbenv, num, size, storep) * __os_malloc -- * The malloc(3) function for DB. * - * PUBLIC: int __os_malloc __P((DB_ENV *, size_t, void *(*)(size_t), void *)); + * PUBLIC: int __os_malloc __P((DB_ENV *, size_t, void *)); */ int -__os_malloc(dbenv, size, db_malloc, storep) +__os_malloc(dbenv, size, storep) DB_ENV *dbenv; size_t size; - void *(*db_malloc) __P((size_t)), *storep; + void *storep; { int ret; void *p; @@ -115,24 +257,26 @@ __os_malloc(dbenv, size, db_malloc, storep) /* Never allocate 0 bytes -- some C libraries don't like it. */ if (size == 0) ++size; + #ifdef DIAGNOSTIC - else - ++size; /* Add room for a guard byte. */ + /* Add room for size and a guard byte. */ + size += sizeof(union __db_alloc) + 1; #endif - /* Some C libraries don't correctly set errno when malloc(3) fails. */ - __os_set_errno(0); - if (db_malloc != NULL) - p = db_malloc(size); - else if (__db_jump.j_malloc != NULL) - p = __db_jump.j_malloc(size); + if (DB_GLOBAL(j_malloc) != NULL) + p = DB_GLOBAL(j_malloc)(size); else p = malloc(size); if (p == NULL) { - ret = __os_get_errno(); - if (ret == 0) { - __os_set_errno(ENOMEM); + /* + * Some C libraries don't correctly set errno when malloc(3) + * fails. We'd like to 0 out errno before calling malloc, + * but it turns out that setting errno is quite expensive on + * Windows/NT in an MT environment. + */ + if ((ret = __os_get_errno()) == 0) { ret = ENOMEM; + __os_set_errno(ENOMEM); } __db_err(dbenv, "malloc: %s: %lu", strerror(ret), (u_long)size); @@ -143,15 +287,12 @@ __os_malloc(dbenv, size, db_malloc, storep) /* * Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional * byte after the memory and set it to a special value that we check - * for when the memory is free'd. This is fine for structures, but - * not quite so fine for strings. There are places in DB where memory - * is allocated sufficient to hold the largest possible string that - * we'll see, and then only some subset of the memory is used. To - * support this usage, the __os_freestr() function checks the byte - * after the string's nul, which may or may not be the last byte in - * the originally allocated memory. + * for when the memory is free'd. */ - memset(p, CLEAR_BYTE, size); /* Initialize guard byte. */ + ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; + + ((union __db_alloc *)p)->size = size; + p = &((union __db_alloc *)p)[1]; #endif *(void **)storep = p; @@ -162,46 +303,50 @@ __os_malloc(dbenv, size, db_malloc, storep) * __os_realloc -- * The realloc(3) function for DB. * - * PUBLIC: int __os_realloc __P((DB_ENV *, - * PUBLIC: size_t, void *(*)(void *, size_t), void *)); + * PUBLIC: int __os_realloc __P((DB_ENV *, size_t, void *)); */ int -__os_realloc(dbenv, size, db_realloc, storep) +__os_realloc(dbenv, size, storep) DB_ENV *dbenv; size_t size; - void *(*db_realloc) __P((void *, size_t)), *storep; + void *storep; { int ret; void *p, *ptr; ptr = *(void **)storep; - /* If we haven't yet allocated anything yet, simply call malloc. */ - if (ptr == NULL && db_realloc == NULL) - return (__os_malloc(dbenv, size, NULL, storep)); - /* Never allocate 0 bytes -- some C libraries don't like it. */ if (size == 0) ++size; + + /* If we haven't yet allocated anything yet, simply call malloc. */ + if (ptr == NULL) + return (__os_malloc(dbenv, size, storep)); + #ifdef DIAGNOSTIC - else - ++size; /* Add room for a guard byte. */ + /* Add room for size and a guard byte. */ + size += sizeof(union __db_alloc) + 1; + + /* Back up to the real begining */ + ptr = &((union __db_alloc *)ptr)[-1]; #endif /* - * Some C libraries don't correctly set errno when realloc(3) fails. - * * Don't overwrite the original pointer, there are places in DB we * try to continue after realloc fails. */ - __os_set_errno(0); - if (db_realloc != NULL) - p = db_realloc(ptr, size); - else if (__db_jump.j_realloc != NULL) - p = __db_jump.j_realloc(ptr, size); + if (DB_GLOBAL(j_realloc) != NULL) + p = DB_GLOBAL(j_realloc)(ptr, size); else p = realloc(ptr, size); if (p == NULL) { + /* + * Some C libraries don't correctly set errno when malloc(3) + * fails. We'd like to 0 out errno before calling malloc, + * but it turns out that setting errno is quite expensive on + * Windows/NT in an MT environment. + */ if ((ret = __os_get_errno()) == 0) { ret = ENOMEM; __os_set_errno(ENOMEM); @@ -212,6 +357,9 @@ __os_realloc(dbenv, size, db_realloc, storep) } #ifdef DIAGNOSTIC ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; /* Initialize guard byte. */ + + ((union __db_alloc *)p)->size = size; + p = &((union __db_alloc *)p)[1]; #endif *(void **)storep = p; @@ -223,64 +371,35 @@ __os_realloc(dbenv, size, db_realloc, storep) * __os_free -- * The free(3) function for DB. * - * PUBLIC: void __os_free __P((void *, size_t)); - */ -void -__os_free(ptr, size) - void *ptr; - size_t size; -{ -#ifdef DIAGNOSTIC - if (size != 0) { - /* - * Check that the guard byte (one past the end of the memory) is - * still CLEAR_BYTE. - */ - if (((u_int8_t *)ptr)[size] != CLEAR_BYTE) - __os_guard(); - - /* Clear memory. */ - if (size != 0) - memset(ptr, CLEAR_BYTE, size); - } -#else - COMPQUIET(size, 0); -#endif - - if (__db_jump.j_free != NULL) - __db_jump.j_free(ptr); - else - free(ptr); -} - -/* - * __os_freestr -- - * The free(3) function for DB, freeing a string. - * - * PUBLIC: void __os_freestr __P((void *)); + * PUBLIC: void __os_free __P((DB_ENV *, void *)); */ void -__os_freestr(ptr) +__os_free(dbenv, ptr) + DB_ENV *dbenv; void *ptr; { #ifdef DIAGNOSTIC - size_t size; - - size = strlen(ptr) + 1; - + int size; /* * Check that the guard byte (one past the end of the memory) is * still CLEAR_BYTE. */ - if (((u_int8_t *)ptr)[size] != CLEAR_BYTE) - __os_guard(); + if (ptr == NULL) + return; + + ptr = &((union __db_alloc *)ptr)[-1]; + size = ((union __db_alloc *)ptr)->size; + if (((u_int8_t *)ptr)[size - 1] != CLEAR_BYTE) + __os_guard(dbenv); /* Clear memory. */ - memset(ptr, CLEAR_BYTE, size); + if (size != 0) + memset(ptr, CLEAR_BYTE, size); #endif + COMPQUIET(dbenv, NULL); - if (__db_jump.j_free != NULL) - __db_jump.j_free(ptr); + if (DB_GLOBAL(j_free) != NULL) + DB_GLOBAL(j_free)(ptr); else free(ptr); } @@ -291,13 +410,10 @@ __os_freestr(ptr) * Complain and abort. */ static void -__os_guard() +__os_guard(dbenv) + DB_ENV *dbenv; { - /* - * Eventually, once we push a DB_ENV handle down to these - * routines, we should use the standard output channels. - */ - fprintf(stderr, "Guard byte incorrect during free.\n"); + __db_err(dbenv, "Guard byte incorrect during free"); abort(); /* NOTREACHED */ } |