Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

gwmem-check.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * gwmem-check.c - memory management wrapper functions, check flavor
00059  *
00060  * This implementation of the gwmem.h interface checks for writes to
00061  * non-allocated areas, and fills freshly allocated and freshly freed
00062  * areas with garbage to prevent their use.  It also reports memory
00063  * leaks.
00064  *
00065  * Design: Memory is allocated with markers before and after the
00066  * area to be used.  These markers can be checked to see if anything
00067  * has written to them.  There is a table of all allocated areas,
00068  * which is used to detect memory leaks and which contains context
00069  * information about each area.
00070  *
00071  * The start marker contains the index into this table, so that it
00072  * can be looked up quickly -- but if the start marker has been damaged,
00073  * the index can still be found by searching the table.
00074  *
00075  * Enlarging an area with realloc is handled by allocating new area,
00076  * copying the old data, and freeing the old area.  This is an expensive
00077  * operation which is avoided by reserving extra space (up to the nearest
00078  * power of two), and only enlarging the area if the requested space is
00079  * larger than this extra space.  The markers are still placed at exactly
00080  * the size requested, so every realloc does mean moving the end marker.
00081  *
00082  * When data is freed, it is overwritten with 0xdeadbeef, so that code
00083  * that tries to use it after freeing will likely crash.  The freed area
00084  * is kept around for a while, to see if anything tries to write to it
00085  * after it's been freed.
00086  * 
00087  * Richard Braakman
00088  * Alexander Malysh (added backtrace support)
00089  */
00090 
00091 #include "gw-config.h"
00092 
00093 #include <stdlib.h>
00094 #include <errno.h>
00095 #include <string.h>
00096 #if HAVE_BACKTRACE
00097 #include <execinfo.h>
00098 #endif
00099 
00100 #include "gwlib.h"
00101 
00102 /* In this module, we must use the real versions so let's undefine the
00103  * accident protectors. */
00104 #undef malloc
00105 #undef realloc
00106 #undef free
00107 
00108 /* Freshly malloced space is filled with NEW_AREA_PATTERN, to break
00109  * code that assumes it is filled with zeroes. */
00110 #define NEW_AREA_PATTERN 0xcafebabe
00111 
00112 /* Freed space is filled with FREE_AREA_PATTERN, to break code that
00113  * tries to read from it after freeing. */
00114 #define FREE_AREA_PATTERN 0xdeadbeef
00115 
00116 /* The marker before an area is filled with START_MARK_PATTERN
00117  * (except for some bookkeeping bytes at the start of the marker). */
00118 #define START_MARK_PATTERN 0xdadaface
00119 
00120 /* The marker beyond an area is filled with END_MARK_PATTERN. */
00121 #define END_MARK_PATTERN 0xadadafec
00122 
00123 /* How many bytes to dump when listing unfreed areas. */
00124 #define MAX_DUMP 16
00125 
00126 static int initialized = 0;
00127 
00128 /* Use slower, more reliable method of detecting memory corruption. */
00129 static int slow = 0;
00130 
00131 /* We have to use a static mutex here, because otherwise the mutex_create
00132  * call would try to allocate memory with gw_malloc before we're
00133  * initialized. */
00134 static Mutex gwmem_lock;
00135 
00136 struct location
00137 {
00138     const char *filename;
00139     long lineno;
00140     const char *function;
00141 };
00142 
00143 /* Duplicating the often-identical location information in every table
00144  * entry uses a lot of memory, but saves the effort of maintaining a
00145  * data structure for it, and keeps access to it fast. */
00146 struct area
00147 {
00148     void *area;    /* The allocated memory area, as seen by caller */
00149     size_t area_size;   /* Size requested by caller */
00150     size_t max_size;    /* Size we can expand area to when reallocing */
00151     struct location allocator;     /* Caller that alloced area */
00152     struct location reallocator;   /* Caller that last realloced area */
00153     struct location claimer;       /* Owner of area, set by caller */
00154 #if HAVE_BACKTRACE
00155     void *frames[10]; /* 10 callers should be sufficient */
00156     size_t frame_size;
00157 #endif
00158 };
00159 
00160 /* Number of bytes to reserve on either side of each allocated area,
00161  * to detect writes just outside the area.  It must be at least large
00162  * enough to hold a long. */
00163 #define MARKER_SIZE 16
00164 
00165 /* 100 MB */
00166 #define MAX_TAB_SIZE (100*1024*1024L)
00167 #define MAX_ALLOCATIONS ((long) (MAX_TAB_SIZE/sizeof(struct area)))
00168 
00169 /* Freed areas are thrown into the free ring.  They are not released
00170  * back to the system until FREE_RING_SIZE other allocations have been
00171  * made.  This is more effective at finding bugs than releasing them
00172  * immediately, because when we eventually release them we can check
00173  * that they have not been tampered with in that time. */
00174 #define FREE_RING_SIZE 1024
00175 
00176 static struct area allocated[MAX_ALLOCATIONS];
00177 static struct area free_ring[FREE_RING_SIZE];
00178 
00179 /* Current number of allocations in the "allocated" table.  They are
00180  * always consecutive and start at the beginning of the table. */
00181 static long num_allocations;
00182 
00183 /* The free ring can wrap around the edges of its array. */
00184 static long free_ring_start;
00185 static long free_ring_len;
00186 
00187 /* The next three are used for informational messages at shutdown */
00188 /* Largest number of allocations we've had at one time */
00189 static long highest_num_allocations;
00190 /* Largest value of the sum of allocated areas we've had at one time */
00191 static long highest_total_size;
00192 /* Current sum of allocated areas */
00193 static long total_size;
00194 
00195 /* Static functions */
00196 
00197 static inline void lock(void)
00198 {
00199     mutex_lock(&gwmem_lock);
00200 }
00201 
00202 static inline void unlock(void)
00203 {
00204     mutex_unlock(&gwmem_lock);
00205 }
00206 
00207 static unsigned long round_pow2(unsigned long num)
00208 {
00209     unsigned long i;
00210 
00211     if (num <= 16)
00212         return 16;
00213 
00214     for (i = 32; i < 0x80000000L; i <<= 1) {
00215         if (num <= i)
00216             return i;
00217     }
00218 
00219     /* We have to handle this case separately; the loop cannot go that
00220      * far because i would overflow. */
00221     if (num <= 0x80000000L)
00222         return 0x80000000L;
00223 
00224     return 0xffffffffL;
00225 }
00226 
00227 /* Fill a memory area with a bit pattern */
00228 static void fill(unsigned char *p, size_t bytes, long pattern)
00229 {
00230     while (bytes > sizeof(pattern)) {
00231         memcpy(p, &pattern, sizeof(pattern));
00232         p += sizeof(pattern);
00233         bytes -= sizeof(pattern);
00234     }
00235     if (bytes > 0)
00236         memcpy(p, &pattern, bytes);
00237 }
00238 
00239 /* Check that a filled memory area has not changed */
00240 static int untouched(unsigned char *p, size_t bytes, long pattern)
00241 {
00242     while (bytes > sizeof(pattern)) {
00243         if (memcmp(p, &pattern, sizeof(pattern)) != 0)
00244             return 0;
00245         p += sizeof(pattern);
00246         bytes -= sizeof(pattern);
00247     }
00248     if (bytes > 0 && memcmp(p, &pattern, bytes) != 0)
00249         return 0;
00250     return 1;
00251 }
00252 
00253 /* Fill the end marker for this area */
00254 static inline void endmark(unsigned char *p, size_t size)
00255 {
00256     fill(p + size, MARKER_SIZE, END_MARK_PATTERN);
00257 }
00258 
00259 /* Fill the start marker for this area, and assign an number to the
00260  * area which can be used for quick lookups later.  The number must
00261  * not be negative. */
00262 static void startmark(unsigned char *p, long number)
00263 {
00264     gw_assert(MARKER_SIZE >= sizeof(long));
00265     gw_assert(number >= 0);
00266 
00267     fill(p - MARKER_SIZE, sizeof(long), number);
00268     fill(p - MARKER_SIZE + sizeof(long),
00269          MARKER_SIZE - sizeof(long), START_MARK_PATTERN);
00270 }
00271 
00272 /* Check that the start marker for this area are intact, and return the
00273  * marker number if it seems intact.  Return a negative number if
00274  * it does not seem intact. */
00275 static long check_startmark(unsigned char *p)
00276 {
00277     long number;
00278     if (!untouched(p - MARKER_SIZE + sizeof(long),
00279                    MARKER_SIZE - sizeof(long), START_MARK_PATTERN))
00280         return -1;
00281     memcpy(&number, p - MARKER_SIZE, sizeof(number));
00282     return number;
00283 }
00284 
00285 static int check_endmark(unsigned char *p, size_t size)
00286 {
00287     if (!untouched(p + size, MARKER_SIZE, END_MARK_PATTERN))
00288         return -1;
00289     return 0;
00290 }
00291 
00292 static int check_marks(struct area *area, long index)
00293 {
00294     int result = 0;
00295 
00296     if (check_startmark(area->area) != index) {
00297         error(0, "Start marker was damaged for area %ld", index);
00298         result = -1;
00299     }
00300     if (check_endmark(area->area, area->area_size) < 0) {
00301         error(0, "End marker was damaged for area %ld", index);
00302         result = -1;
00303     }
00304 
00305     return result;
00306 }
00307 
00308 static void dump_area(struct area *area)
00309 {
00310     debug("gwlib.gwmem", 0, "Area %p, size %ld, max_size %ld",
00311           area->area, (long) area->area_size, (long) area->max_size);
00312     debug("gwlib.gwmem", 0, "Allocated by %s() at %s:%ld",
00313           area->allocator.function,
00314           area->allocator.filename,
00315           area->allocator.lineno);
00316     if (area->reallocator.function) {
00317         debug("gwlib.gwmem", 0, "Re-allocated by %s() at %s:%ld",
00318               area->reallocator.function,
00319               area->reallocator.filename,
00320               area->reallocator.lineno);
00321     }
00322     if (area->claimer.function) {
00323         debug("gwlib.gwmem", 0, "Claimed by %s() at %s:%ld",
00324               area->claimer.function,
00325               area->claimer.filename,
00326               area->claimer.lineno);
00327     }
00328     if (area->area_size > 0) {
00329         size_t i;
00330         unsigned char *p;
00331         char buf[MAX_DUMP * 3 + 1];
00332 
00333         p = area->area;
00334         buf[0] = '\0';
00335         for (i = 0; i < area->area_size && i < MAX_DUMP; ++i)
00336             sprintf(strchr(buf, '\0'), "%02x ", p[i]);
00337 
00338         debug("gwlib.gwmem", 0, "Contents of area (first %d bytes):", MAX_DUMP);
00339         debug("gwlib.gwmem", 0, "  %s", buf);
00340     }
00341 #if HAVE_BACKTRACE
00342     {
00343         size_t i;
00344         char **strings = backtrace_symbols(area->frames, area->frame_size);
00345         debug("gwlib.gwmem", 0, "Backtrace of last malloc/realloc:");
00346         for (i = 0; i < area->frame_size; i++) {
00347             if (strings != NULL)
00348                 debug("gwlib.gwmem", 0, "%s", strings[i]);
00349             else
00350                 debug("gwlib.gwmem", 0, "%p", area->frames[i]);
00351         }
00352         free(strings);
00353     }
00354 #endif
00355 }
00356 
00357 static struct area *find_area(unsigned char *p)
00358 {
00359     long index;
00360     struct area *area;
00361     long suspicious_pointer;
00362     unsigned long p_ul;
00363 
00364     gw_assert(p != NULL);
00365 
00366     p_ul = (unsigned long) p;
00367     suspicious_pointer =
00368         (sizeof(p) == sizeof(long) &&
00369          (p_ul == NEW_AREA_PATTERN || p_ul == FREE_AREA_PATTERN ||
00370       p_ul == START_MARK_PATTERN || p_ul == END_MARK_PATTERN));
00371 
00372     if (slow || suspicious_pointer) {
00373         /* Extra check, which does not touch the (perhaps not allocated)
00374      * memory area.  It's slow, but may help pinpoint problems that
00375      * would otherwise cause segfaults. */
00376         for (index = 0; index < num_allocations; index++) {
00377             if (allocated[index].area == p)
00378                 break;
00379         }
00380         if (index == num_allocations) {
00381             error(0, "Area %p not found in allocation table.", p);
00382             return NULL;
00383         }
00384     }
00385 
00386     index = check_startmark(p);
00387     if (index >= 0 && index < num_allocations &&
00388         allocated[index].area == p) {
00389         area = &allocated[index];
00390         if (check_endmark(p, area->area_size) < 0) {
00391             error(0, "End marker was damaged for area %p", p);
00392             dump_area(area);
00393         }
00394         return area;
00395     }
00396 
00397     error(0, "Start marker was damaged for area %p", p);
00398     for (index = 0; index < num_allocations; index++) {
00399         if (allocated[index].area == p) {
00400             area = &allocated[index];
00401             dump_area(area);
00402             return area;
00403         }
00404     }
00405 
00406     error(0, "Could not find area information.");
00407     return NULL;
00408 }
00409 
00410 static void change_total_size(long change)
00411 {
00412     total_size += change;
00413     if (total_size > highest_total_size)
00414         highest_total_size = total_size;
00415 }
00416 
00417 static struct area *record_allocation(unsigned char *p, size_t size,
00418                                                   const char *filename, long lineno, const char *function)
00419 {
00420     struct area *area;
00421     static struct area empty_area;
00422 
00423     if (num_allocations == MAX_ALLOCATIONS) {
00424         panic(0, "Too many concurrent allocations.");
00425     }
00426 
00427     area = &allocated[num_allocations];
00428     *area = empty_area;
00429     area->area = p;
00430     area->area_size = size;
00431     area->max_size = size;
00432     area->allocator.filename = filename;
00433     area->allocator.lineno = lineno;
00434     area->allocator.function = function;
00435 #if HAVE_BACKTRACE
00436     area->frame_size = backtrace(area->frames, sizeof(area->frames) / sizeof(void*));
00437 #endif
00438 
00439     startmark(area->area, num_allocations);
00440     endmark(area->area, area->area_size);
00441 
00442     num_allocations++;
00443     if (num_allocations > highest_num_allocations)
00444         highest_num_allocations = num_allocations;
00445     change_total_size(size);
00446 
00447     return area;
00448 }
00449 
00450 static void remove_allocation(struct area *area)
00451 {
00452     change_total_size(-1*area->area_size);
00453     num_allocations--;
00454     if (area == &allocated[num_allocations])
00455         return;
00456     check_marks(&allocated[num_allocations], num_allocations);
00457     *area = allocated[num_allocations];
00458     startmark(area->area, area - allocated);
00459 }
00460 
00461 static void drop_from_free_ring(long index)
00462 {
00463     struct area *area;
00464 
00465     area = &free_ring[index];
00466     if (check_marks(area, index) < 0 ||
00467         !untouched(area->area, area->area_size, FREE_AREA_PATTERN)) {
00468         error(0, "Freed area %p has been tampered with.", area->area);
00469         dump_area(area);
00470     }
00471     free((unsigned char *)area->area - MARKER_SIZE);
00472 }
00473 
00474 static void put_on_free_ring(struct area *area)
00475 {
00476     /* Simple case: We're still filling the free ring. */
00477     if (free_ring_len < FREE_RING_SIZE) {
00478         free_ring[free_ring_len] = *area;
00479         startmark(area->area, free_ring_len);
00480         free_ring_len++;
00481         return;
00482     }
00483 
00484     /* Normal case: We need to check and release a free ring entry,
00485      * then put this one in its place. */
00486 
00487     drop_from_free_ring(free_ring_start);
00488     free_ring[free_ring_start] = *area;
00489     startmark(area->area, free_ring_start);
00490     free_ring_start = (free_ring_start + 1) % FREE_RING_SIZE;
00491 }
00492 
00493 static void free_area(struct area *area)
00494 {
00495     fill(area->area, area->area_size, FREE_AREA_PATTERN);
00496     put_on_free_ring(area);
00497     remove_allocation(area);
00498 }
00499 
00500 void gw_check_init_mem(int slow_flag)
00501 {
00502     mutex_init_static(&gwmem_lock);
00503     slow = slow_flag;
00504     initialized = 1;
00505 }
00506 
00507 void gw_check_shutdown(void)
00508 {
00509     mutex_destroy(&gwmem_lock);
00510     initialized = 0;
00511 }
00512 
00513 void *gw_check_malloc(size_t size, const char *filename, long lineno,
00514                       const char *function)
00515 {
00516     unsigned char *p;
00517 
00518     gw_assert(initialized);
00519 
00520     /* ANSI C89 says malloc(0) is implementation-defined.  Avoid it. */
00521     gw_assert(size > 0);
00522 
00523     p = malloc(size + 2 * MARKER_SIZE);
00524     if (p == NULL)
00525         panic(errno, "Memory allocation of %ld bytes failed.", (long)size);
00526     p += MARKER_SIZE;
00527 
00528     lock();
00529     fill(p, size, NEW_AREA_PATTERN);
00530     record_allocation(p, size, filename, lineno, function);
00531     unlock();
00532 
00533     return p;
00534 }
00535 
00536 void *gw_check_realloc(void *p, size_t size, const char *filename,
00537                        long lineno, const char *function)
00538 {
00539     struct area *area;
00540 
00541     if (p == NULL)
00542         return gw_check_malloc(size, filename, lineno, function);
00543 
00544     gw_assert(initialized);
00545     gw_assert(size > 0);
00546 
00547     lock();
00548     area = find_area(p);
00549     if (!area) {
00550         unlock();
00551         panic(0, "Realloc called on non-allocated area");
00552     }
00553 
00554     if (size == area->area_size) {
00555         /* No changes */
00556     } else if (size <= area->max_size) {
00557         change_total_size(size - area->area_size);
00558         area->area_size = size;
00559         endmark(p, size);
00560     } else if (size > area->max_size) {
00561         /* The current block is not large enough for the reallocation.
00562          * We will allocate a new block, copy the data over, and free
00563          * the old block.  We round the size up to a power of two,
00564          * to prevent frequent reallocations. */
00565         struct area *new_area;
00566         size_t new_size;
00567         unsigned char *new_p;
00568 
00569         new_size = round_pow2(size + 2 * MARKER_SIZE);
00570         new_p = malloc(new_size);
00571         new_size -= 2 * MARKER_SIZE;
00572         new_p += MARKER_SIZE;
00573         memcpy(new_p, p, area->area_size);
00574         fill(new_p + area->area_size, size - area->area_size,
00575              NEW_AREA_PATTERN);
00576         new_area = record_allocation(new_p, size,
00577                                      area->allocator.filename,
00578                                      area->allocator.lineno,
00579                                      area->allocator.function);
00580         new_area->max_size = new_size;
00581         free_area(area);
00582 
00583         p = new_p;
00584         area = new_area;
00585     }
00586 
00587     area->reallocator.filename = filename;
00588     area->reallocator.lineno = lineno;
00589     area->reallocator.function = function;
00590     unlock();
00591     return p;
00592 }
00593 
00594 void gw_check_free(void *p, const char *filename, long lineno,
00595                    const char *function)
00596 {
00597     struct area *area;
00598     gw_assert(initialized);
00599 
00600     if (p == NULL)
00601         return;
00602 
00603     lock();
00604     area = find_area(p);
00605     if (!area) {
00606         unlock();
00607         panic(0, "Free called on non-allocated area");
00608     }
00609 
00610     free_area(area);
00611     unlock();
00612 }
00613 
00614 char *gw_check_strdup(const char *str, const char *filename, long lineno,
00615                       const char *function)
00616 {
00617     char *copy;
00618 
00619     gw_assert(initialized);
00620     gw_assert(str != NULL);
00621 
00622     copy = gw_check_malloc(strlen(str) + 1, filename, lineno, function);
00623     strcpy(copy, str);
00624     return copy;
00625 }
00626 
00627 void *gw_check_claim_area(void *p, const char *filename, long lineno,
00628                           const char *function)
00629 {
00630     struct area *area;
00631 
00632     /* Allow this for the convenience of wrapper macros. */
00633     if (p == NULL)
00634         return NULL;
00635 
00636     lock();
00637     area = find_area(p);
00638     if (!area) {
00639         unlock();
00640         panic(0, "Claim_area called on non-allocated area");
00641     }
00642 
00643     area->claimer.filename = filename;
00644     area->claimer.lineno = lineno;
00645     area->claimer.function = function;
00646     unlock();
00647 
00648     /* For convenience of calling macros */
00649     return p;
00650 }
00651 
00652 void gw_check_check_leaks(void)
00653 {
00654     long calculated_size;
00655     long index;
00656 
00657     gw_assert(initialized);
00658     lock();
00659 
00660     for (index = 0; index < free_ring_len; index++) {
00661         drop_from_free_ring(index);
00662     }
00663     free_ring_len = 0;
00664 
00665     calculated_size = 0;
00666     for (index = 0; index < num_allocations; index++) {
00667         calculated_size += allocated[index].area_size;
00668     }
00669     gw_assert(calculated_size == total_size);
00670 
00671     debug("gwlib.gwmem", 0, "----------------------------------------");
00672     debug("gwlib.gwmem", 0, "Current allocations: %ld areas, %ld bytes",
00673           num_allocations, total_size);
00674     debug("gwlib.gwmem", 0, "Highest number of allocations: %ld areas",
00675           highest_num_allocations);
00676     debug("gwlib.gwmem", 0, "Highest memory usage: %ld bytes",
00677           highest_total_size);
00678     for (index = 0; index < num_allocations; index++) {
00679         check_marks(&allocated[index], index);
00680         dump_area(&allocated[index]);
00681     }
00682 
00683     unlock();
00684 }
00685 
00686 int gw_check_is_allocated(void *p)
00687 {
00688     struct area *area;
00689 
00690     lock();
00691     area = find_area(p);
00692     unlock();
00693     return area != NULL;
00694 }
00695 
00696 long gw_check_area_size(void *p)
00697 {
00698     struct area *area;
00699     size_t size;
00700 
00701     lock();
00702     area = find_area(p);
00703     if (!area) {
00704         unlock();
00705         warning(0, "Area_size called on non-allocated area %p", p);
00706         return -1;
00707     }
00708     size = area->area_size;
00709     unlock();
00710     return size;
00711 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.