📄 gwmem-check.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwmem-check.c - memory management wrapper functions, check flavor * * This implementation of the gwmem.h interface checks for writes to * non-allocated areas, and fills freshly allocated and freshly freed * areas with garbage to prevent their use. It also reports memory * leaks. * * Design: Memory is allocated with markers before and after the * area to be used. These markers can be checked to see if anything * has written to them. There is a table of all allocated areas, * which is used to detect memory leaks and which contains context * information about each area. * * The start marker contains the index into this table, so that it * can be looked up quickly -- but if the start marker has been damaged, * the index can still be found by searching the table. * * Enlarging an area with realloc is handled by allocating new area, * copying the old data, and freeing the old area. This is an expensive * operation which is avoided by reserving extra space (up to the nearest * power of two), and only enlarging the area if the requested space is * larger than this extra space. The markers are still placed at exactly * the size requested, so every realloc does mean moving the end marker. * * When data is freed, it is overwritten with 0xdeadbeef, so that code * that tries to use it after freeing will likely crash. The freed area * is kept around for a while, to see if anything tries to write to it * after it's been freed. * * Richard Braakman */#include <stdlib.h>#include <errno.h>#include <string.h>#include "gwlib.h"/* In this module, we must use the real versions so let's undefine the * accident protectors. */#undef malloc#undef realloc#undef free/* Freshly malloced space is filled with NEW_AREA_PATTERN, to break * code that assumes it is filled with zeroes. */#define NEW_AREA_PATTERN 0xcafebabe/* Freed space is filled with FREE_AREA_PATTERN, to break code that * tries to read from it after freeing. */#define FREE_AREA_PATTERN 0xdeadbeef/* The marker before an area is filled with START_MARK_PATTERN * (except for some bookkeeping bytes at the start of the marker). */#define START_MARK_PATTERN 0xdadaface/* The marker beyond an area is filled with END_MARK_PATTERN. */#define END_MARK_PATTERN 0xadadafec/* How many bytes to dump when listing unfreed areas. */#define MAX_DUMP 16static int initialized = 0;/* Use slower, more reliable method of detecting memory corruption. */static int slow = 0;/* We have to use a static mutex here, because otherwise the mutex_create * call would try to allocate memory with gw_malloc before we're * initialized. */static Mutex gwmem_lock;struct location{ const char *filename; long lineno; const char *function;};/* Duplicating the often-identical location information in every table * entry uses a lot of memory, but saves the effort of maintaining a * data structure for it, and keeps access to it fast. */struct area{ void *area; /* The allocated memory area, as seen by caller */ size_t area_size; /* Size requested by caller */ size_t max_size; /* Size we can expand area to when reallocing */ struct location allocator; /* Caller that alloced area */ struct location reallocator; /* Caller that last realloced area */ struct location claimer; /* Owner of area, set by caller */};/* Number of bytes to reserve on either side of each allocated area, * to detect writes just outside the area. It must be at least large * enough to hold a long. */#define MARKER_SIZE 16#define MAX_TAB_SIZE (1024*1024L)#define MAX_ALLOCATIONS ((long) (MAX_TAB_SIZE/sizeof(struct area)))/* Freed areas are thrown into the free ring. They are not released * back to the system until FREE_RING_SIZE other allocations have been * made. This is more effective at finding bugs than releasing them * immediately, because when we eventually release them we can check * that they have not been tampered with in that time. */#define FREE_RING_SIZE 1024static struct area allocated[MAX_ALLOCATIONS];static struct area free_ring[FREE_RING_SIZE];/* Current number of allocations in the "allocated" table. They are * always consecutive and start at the beginning of the table. */static long num_allocations;/* The free ring can wrap around the edges of its array. */static long free_ring_start;static long free_ring_len;/* The next three are used for informational messages at shutdown *//* Largest number of allocations we've had at one time */static long highest_num_allocations;/* Largest value of the sum of allocated areas we've had at one time */static long highest_total_size;/* Current sum of allocated areas */static long total_size;/* Static functions */static void lock(void){ mutex_lock(&gwmem_lock);}static void unlock(void){ mutex_unlock(&gwmem_lock);}static unsigned long round_pow2(unsigned long num){ unsigned long i; if (num <= 16) return 16; for (i = 32; i < 0x80000000L; i <<= 1) { if (num <= i) return i; } /* We have to handle this case separately; the loop cannot go that * far because i would overflow. */ if (num <= 0x80000000L) return 0x80000000L; return 0xffffffffL;}/* Fill a memory area with a bit pattern */static void fill(unsigned char *p, size_t bytes, long pattern){ while (bytes > sizeof(pattern)) { memcpy(p, &pattern, sizeof(pattern)); p += sizeof(pattern); bytes -= sizeof(pattern); } if (bytes > 0) memcpy(p, &pattern, bytes);}/* Check that a filled memory area has not changed */static int untouched(unsigned char *p, size_t bytes, long pattern){ while (bytes > sizeof(pattern)) { if (memcmp(p, &pattern, sizeof(pattern)) != 0) return 0; p += sizeof(pattern); bytes -= sizeof(pattern); } if (bytes > 0 && memcmp(p, &pattern, bytes) != 0) return 0; return 1;}/* Fill the end marker for this area */static void endmark(unsigned char *p, size_t size){ fill(p + size, MARKER_SIZE, END_MARK_PATTERN);}/* Fill the start marker for this area, and assign an number to the * area which can be used for quick lookups later. The number must * not be negative. */static void startmark(unsigned char *p, long number){ gw_assert(MARKER_SIZE >= sizeof(long)); gw_assert(number >= 0); fill(p - MARKER_SIZE, sizeof(long), number); fill(p - MARKER_SIZE + sizeof(long), MARKER_SIZE - sizeof(long), START_MARK_PATTERN);}/* Check that the start marker for this area are intact, and return the * marker number if it seems intact. Return a negative number if * it does not seem intact. */static long check_startmark(unsigned char *p){ long number; if (!untouched(p - MARKER_SIZE + sizeof(long), MARKER_SIZE - sizeof(long), START_MARK_PATTERN)) return -1; memcpy(&number, p - MARKER_SIZE, sizeof(number)); return number;}static int check_endmark(unsigned char *p, size_t size){ if (!untouched(p + size, MARKER_SIZE, END_MARK_PATTERN)) return -1; return 0;}static int check_marks(struct area *area, long index){ int result = 0; if (check_startmark(area->area) != index) { error(0, "Start marker was damaged for area %ld", index); result = -1; } if (check_endmark(area->area, area->area_size) < 0) { error(0, "End marker was damaged for area %ld", index); result = -1; } return result;}static void dump_area(struct area *area){ debug("gwlib.gwmem", 0, "Area %p, size %ld, max_size %ld", area->area, (long) area->area_size, (long) area->max_size); debug("gwlib.gwmem", 0, "Allocated by %s() at %s:%ld", area->allocator.function, area->allocator.filename, area->allocator.lineno); if (area->reallocator.function) { debug("gwlib.gwmem", 0, "Re-allocated by %s() at %s:%ld", area->reallocator.function, area->reallocator.filename, area->reallocator.lineno); } if (area->claimer.function) { debug("gwlib.gwmem", 0, "Claimed by %s() at %s:%ld", area->claimer.function, area->claimer.filename, area->claimer.lineno); } if (area->area_size > 0) { size_t i; unsigned char *p; char buf[MAX_DUMP * 3 + 1]; p = area->area; buf[0] = '\0'; for (i = 0; i < area->area_size && i < MAX_DUMP; ++i) sprintf(strchr(buf, '\0'), "%02x ", p[i]); debug("gwlib.gwmem", 0, "Contents of area (first %d bytes):", MAX_DUMP); debug("gwlib.gwmem", 0, " %s", buf); }}static struct area *find_area(unsigned char *p){ long index; struct area *area; long suspicious_pointer; unsigned long p_ul; gw_assert(p != NULL); p_ul = (unsigned long) p; suspicious_pointer =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -