1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_alloc.c,v 12.18 2008/04/11 00:46:48 alexg Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13#ifdef DIAGNOSTIC
14static void __os_guard __P((ENV *));
15
16typedef union {
17	size_t size;
18	double align;
19} db_allocinfo_t;
20#endif
21
22/*
23 * !!!
24 * Correct for systems that return NULL when you allocate 0 bytes of memory.
25 * There are several places in DB where we allocate the number of bytes held
26 * by the key/data item, and it can be 0.  Correct here so that malloc never
27 * returns a NULL for that reason (which behavior is permitted by ANSI).  We
28 * could make these calls macros on non-Alpha architectures (that's where we
29 * saw the problem), but it's probably not worth the autoconf complexity.
30 *
31 * !!!
32 * Correct for systems that don't set errno when malloc and friends fail.
33 *
34 *	Out of memory.
35 *	We wish to hold the whole sky,
36 *	But we never will.
37 */
38
39/*
40 * __os_umalloc --
41 *	Allocate memory to be used by the application.
42 *
43 *	Use, in order of preference, the allocation function specified to the
44 *	ENV handle, the allocation function specified as a replacement for
45 *	the library malloc, or the library malloc().
46 *
47 * PUBLIC: int __os_umalloc __P((ENV *, size_t, void *));
48 */
49int
50__os_umalloc(env, size, storep)
51	ENV *env;
52	size_t size;
53	void *storep;
54{
55	DB_ENV *dbenv;
56	int ret;
57
58	dbenv = env == NULL ? NULL : env->dbenv;
59
60	/* Never allocate 0 bytes -- some C libraries don't like it. */
61	if (size == 0)
62		++size;
63
64	if (dbenv == NULL || dbenv->db_malloc == NULL) {
65		if (DB_GLOBAL(j_malloc) != NULL)
66			*(void **)storep = DB_GLOBAL(j_malloc)(size);
67		else
68			*(void **)storep = malloc(size);
69		if (*(void **)storep == NULL) {
70			/*
71			 *  Correct error return, see __os_malloc.
72			 */
73			if ((ret = __os_get_errno_ret_zero()) == 0) {
74				ret = ENOMEM;
75				__os_set_errno(ENOMEM);
76			}
77			__db_err(env, ret, "malloc: %lu", (u_long)size);
78			return (ret);
79		}
80		return (0);
81	}
82
83	if ((*(void **)storep = dbenv->db_malloc(size)) == NULL) {
84		__db_errx(env,
85		    "user-specified malloc function returned NULL");
86		return (ENOMEM);
87	}
88
89	return (0);
90}
91
92/*
93 * __os_urealloc --
94 *	Allocate memory to be used by the application.
95 *
96 *	A realloc(3) counterpart to __os_umalloc's malloc(3).
97 *
98 * PUBLIC: int __os_urealloc __P((ENV *, size_t, void *));
99 */
100int
101__os_urealloc(env, size, storep)
102	ENV *env;
103	size_t size;
104	void *storep;
105{
106	DB_ENV *dbenv;
107	int ret;
108	void *ptr;
109
110	dbenv = env == NULL ? NULL : env->dbenv;
111	ptr = *(void **)storep;
112
113	/* Never allocate 0 bytes -- some C libraries don't like it. */
114	if (size == 0)
115		++size;
116
117	if (dbenv == NULL || dbenv->db_realloc == NULL) {
118		if (ptr == NULL)
119			return (__os_umalloc(env, size, storep));
120
121		if (DB_GLOBAL(j_realloc) != NULL)
122			*(void **)storep = DB_GLOBAL(j_realloc)(ptr, size);
123		else
124			*(void **)storep = realloc(ptr, size);
125		if (*(void **)storep == NULL) {
126			/*
127			 * Correct errno, see __os_realloc.
128			 */
129			if ((ret = __os_get_errno_ret_zero()) == 0) {
130				ret = ENOMEM;
131				__os_set_errno(ENOMEM);
132			}
133			__db_err(env, ret, "realloc: %lu", (u_long)size);
134			return (ret);
135		}
136		return (0);
137	}
138
139	if ((*(void **)storep = dbenv->db_realloc(ptr, size)) == NULL) {
140		__db_errx(env,
141		    "User-specified realloc function returned NULL");
142		return (ENOMEM);
143	}
144
145	return (0);
146}
147
148/*
149 * __os_ufree --
150 *	Free memory used by the application.
151 *
152 *	A free(3) counterpart to __os_umalloc's malloc(3).
153 *
154 * PUBLIC: void __os_ufree __P((ENV *, void *));
155 */
156void
157__os_ufree(env, ptr)
158	ENV *env;
159	void *ptr;
160{
161	DB_ENV *dbenv;
162
163	dbenv = env == NULL ? NULL : env->dbenv;
164
165	if (dbenv != NULL && dbenv->db_free != NULL)
166		dbenv->db_free(ptr);
167	else if (DB_GLOBAL(j_free) != NULL)
168		DB_GLOBAL(j_free)(ptr);
169	else
170		free(ptr);
171}
172
173/*
174 * __os_strdup --
175 *	The strdup(3) function for DB.
176 *
177 * PUBLIC: int __os_strdup __P((ENV *, const char *, void *));
178 */
179int
180__os_strdup(env, str, storep)
181	ENV *env;
182	const char *str;
183	void *storep;
184{
185	size_t size;
186	int ret;
187	void *p;
188
189	*(void **)storep = NULL;
190
191	size = strlen(str) + 1;
192	if ((ret = __os_malloc(env, size, &p)) != 0)
193		return (ret);
194
195	memcpy(p, str, size);
196
197	*(void **)storep = p;
198	return (0);
199}
200
201/*
202 * __os_calloc --
203 *	The calloc(3) function for DB.
204 *
205 * PUBLIC: int __os_calloc __P((ENV *, size_t, size_t, void *));
206 */
207int
208__os_calloc(env, num, size, storep)
209	ENV *env;
210	size_t num, size;
211	void *storep;
212{
213	int ret;
214
215	size *= num;
216	if ((ret = __os_malloc(env, size, storep)) != 0)
217		return (ret);
218
219	memset(*(void **)storep, 0, size);
220
221	return (0);
222}
223
224/*
225 * __os_malloc --
226 *	The malloc(3) function for DB.
227 *
228 * PUBLIC: int __os_malloc __P((ENV *, size_t, void *));
229 */
230int
231__os_malloc(env, size, storep)
232	ENV *env;
233	size_t size;
234	void *storep;
235{
236	int ret;
237	void *p;
238
239	*(void **)storep = NULL;
240
241	/* Never allocate 0 bytes -- some C libraries don't like it. */
242	if (size == 0)
243		++size;
244
245#ifdef DIAGNOSTIC
246	/* Add room for size and a guard byte. */
247	size += sizeof(db_allocinfo_t) + 1;
248#endif
249
250	if (DB_GLOBAL(j_malloc) != NULL)
251		p = DB_GLOBAL(j_malloc)(size);
252	else
253		p = malloc(size);
254	if (p == NULL) {
255		/*
256		 * Some C libraries don't correctly set errno when malloc(3)
257		 * fails.  We'd like to 0 out errno before calling malloc,
258		 * but it turns out that setting errno is quite expensive on
259		 * Windows/NT in an MT environment.
260		 */
261		if ((ret = __os_get_errno_ret_zero()) == 0) {
262			ret = ENOMEM;
263			__os_set_errno(ENOMEM);
264		}
265		__db_err(env, ret, "malloc: %lu", (u_long)size);
266		return (ret);
267	}
268
269#ifdef DIAGNOSTIC
270	/* Overwrite memory. */
271	memset(p, CLEAR_BYTE, size);
272
273	/*
274	 * Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional
275	 * byte after the memory and set it to a special value that we check
276	 * for when the memory is free'd.
277	 */
278	((u_int8_t *)p)[size - 1] = CLEAR_BYTE;
279
280	((db_allocinfo_t *)p)->size = size;
281	p = &((db_allocinfo_t *)p)[1];
282#endif
283	*(void **)storep = p;
284
285	return (0);
286}
287
288/*
289 * __os_realloc --
290 *	The realloc(3) function for DB.
291 *
292 * PUBLIC: int __os_realloc __P((ENV *, size_t, void *));
293 */
294int
295__os_realloc(env, size, storep)
296	ENV *env;
297	size_t size;
298	void *storep;
299{
300	int ret;
301	void *p, *ptr;
302
303	ptr = *(void **)storep;
304
305	/* Never allocate 0 bytes -- some C libraries don't like it. */
306	if (size == 0)
307		++size;
308
309	/* If we haven't yet allocated anything yet, simply call malloc. */
310	if (ptr == NULL)
311		return (__os_malloc(env, size, storep));
312
313#ifdef DIAGNOSTIC
314	/* Add room for size and a guard byte. */
315	size += sizeof(db_allocinfo_t) + 1;
316
317	/* Back up to the real beginning */
318	ptr = &((db_allocinfo_t *)ptr)[-1];
319
320	{
321		size_t s;
322
323		s = ((db_allocinfo_t *)ptr)->size;
324		if (((u_int8_t *)ptr)[s - 1] != CLEAR_BYTE)
325			 __os_guard(env);
326	}
327#endif
328
329	/*
330	 * Don't overwrite the original pointer, there are places in DB we
331	 * try to continue after realloc fails.
332	 */
333	if (DB_GLOBAL(j_realloc) != NULL)
334		p = DB_GLOBAL(j_realloc)(ptr, size);
335	else
336		p = realloc(ptr, size);
337	if (p == NULL) {
338		/*
339		 * Some C libraries don't correctly set errno when malloc(3)
340		 * fails.  We'd like to 0 out errno before calling malloc,
341		 * but it turns out that setting errno is quite expensive on
342		 * Windows/NT in an MT environment.
343		 */
344		if ((ret = __os_get_errno_ret_zero()) == 0) {
345			ret = ENOMEM;
346			__os_set_errno(ENOMEM);
347		}
348		__db_err(env, ret, "realloc: %lu", (u_long)size);
349		return (ret);
350	}
351#ifdef DIAGNOSTIC
352	((u_int8_t *)p)[size - 1] = CLEAR_BYTE;	/* Initialize guard byte. */
353
354	((db_allocinfo_t *)p)->size = size;
355	p = &((db_allocinfo_t *)p)[1];
356#endif
357
358	*(void **)storep = p;
359
360	return (0);
361}
362
363/*
364 * __os_free --
365 *	The free(3) function for DB.
366 *
367 * PUBLIC: void __os_free __P((ENV *, void *));
368 */
369void
370__os_free(env, ptr)
371	ENV *env;
372	void *ptr;
373{
374#ifdef DIAGNOSTIC
375	size_t size;
376#endif
377
378	/*
379	 * ANSI C requires free(NULL) work.  Don't depend on the underlying
380	 * library.
381	 */
382	if (ptr == NULL)
383		return;
384
385#ifdef DIAGNOSTIC
386	/*
387	 * Check that the guard byte (one past the end of the memory) is
388	 * still CLEAR_BYTE.
389	 */
390	ptr = &((db_allocinfo_t *)ptr)[-1];
391	size = ((db_allocinfo_t *)ptr)->size;
392	if (((u_int8_t *)ptr)[size - 1] != CLEAR_BYTE)
393		 __os_guard(env);
394
395	/* Overwrite memory. */
396	if (size != 0)
397		memset(ptr, CLEAR_BYTE, size);
398#else
399	COMPQUIET(env, NULL);
400#endif
401
402	if (DB_GLOBAL(j_free) != NULL)
403		DB_GLOBAL(j_free)(ptr);
404	else
405		free(ptr);
406}
407
408#ifdef DIAGNOSTIC
409/*
410 * __os_guard --
411 *	Complain and abort.
412 */
413static void
414__os_guard(env)
415	ENV *env;
416{
417	__db_errx(env, "Guard byte incorrect during free");
418	__os_abort(env);
419	/* NOTREACHED */
420}
421#endif
422
423/*
424 * __ua_memcpy --
425 *	Copy memory to memory without relying on any kind of alignment.
426 *
427 *	There are places in DB that we have unaligned data, for example,
428 *	when we've stored a structure in a log record as a DBT, and now
429 *	we want to look at it.  Unfortunately, if you have code like:
430 *
431 *		struct a {
432 *			int x;
433 *		} *p;
434 *
435 *		void *func_argument;
436 *		int local;
437 *
438 *		p = (struct a *)func_argument;
439 *		memcpy(&local, p->x, sizeof(local));
440 *
441 *	compilers optimize to use inline instructions requiring alignment,
442 *	and records in the log don't have any particular alignment.  (This
443 *	isn't a compiler bug, because it's a structure they're allowed to
444 *	assume alignment.)
445 *
446 *	Casting the memcpy arguments to (u_int8_t *) appears to work most
447 *	of the time, but we've seen examples where it wasn't sufficient
448 *	and there's nothing in ANSI C that requires that work.
449 *
450 * PUBLIC: void *__ua_memcpy __P((void *, const void *, size_t));
451 */
452void *
453__ua_memcpy(dst, src, len)
454	void *dst;
455	const void *src;
456	size_t len;
457{
458	return ((void *)memcpy(dst, src, len));
459}
460