libclamav/mpool.c
e21657df
 /*
  *  Copyright (C) 2008 Sourcefire, Inc.
  *
946bd266
  *  Authors: aCaB <acab@clamav.net>
e21657df
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 
 /* a naive pool allocator */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #ifdef USE_MPOOL
160930d4
 
e21657df
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #if HAVE_STRING_H
 #include <string.h>
 #endif
11195c0b
 #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H)
 #include <sys/mman.h>
 #endif
e21657df
 #include <stddef.h>
 
946bd266
 #include "others.h"
ad0fd728
 #include "str.h"
d6e1ef16
 #include "readdb.h"
e21657df
 
d068119a
 /*#define CL_DEBUG*/
1b802d3c
 #ifdef CL_DEBUG
 #include <assert.h>
d068119a
 #define MPOOLMAGIC 0xadde
1b802d3c
 #define ALLOCPOISON 0x5a
 #define FREEPOISON 0xde
 #endif
 
d068119a
 /*#define DEBUGMPOOL
 #define EXIT_ON_FLUSH*/
e21657df
 #ifdef DEBUGMPOOL
7866b37c
 #define spam(...) cli_warnmsg( __VA_ARGS__)
e21657df
 #else
1b802d3c
 static inline void spam(const char *fmt, ...) { fmt = fmt; } /* gcc STFU */
e21657df
 #endif
 
 #include "mpool.h"
 
34e79a80
 #define MIN_FRAGSIZE 262144
e21657df
 
0281fb4d
 #if SIZEOF_VOID_P==8
 static const unsigned int fragsz[] = {
8a88afcf
 /* SIZE,      MAX   */
       8, /*  783293 */
      11, /*    4445 */
      13, /*   10160 */
      15, /*    8365 */
      16, /*   24857 */
      17, /*   24630 */
      19, /*  136608 */
      20, /*   90714 */
      21, /*  176421 */
      23, /*   52766 */
      24, /*  161770 */
      25, /*   38590 */
      29, /*   18023 */
      31, /*   15987 */
      32, /*  104854 */
      33, /*    9312 */
      35, /*  371084 */
      41, /*    5068 */
      43, /*  142581 */
      44, /*   99347 */
      45, /*   74173 */
      47, /*   31516 */
      48, /*  320748 */
      49, /*   45256 */
      56, /*    1543 */
      64, /*     963 */
      74, /*   12397 */
      76, /*   17846 */
      79, /*   15721 */
      80, /*  599771 */
      81, /*    5618 */
      93, /*    2101 */
      97, /*    2425 */
     104, /*    1495 */
     113, /*    3107 */
     116, /*    2403 */
     123, /*    1415 */
     128, /*    2368 */
     131, /*    2697 */
     143, /*   10539 */
     150, /*   10982 */
     151, /*    6869 */
     152, /*   28254 */
     153, /*   13670 */
     229, /*     501 */
     256, /*     830 */
     304, /*     834 */
     320, /*     377 */
     512, /*      17 */
    1024, /*       6 */
    2048, /*       3 */
    2056, /*   10116 */
    4096, /*       3 */
    8192, /*       2 */
    9334, /*       3 */
   12163, /*       4 */
   16392, /*     257 */
   18440, /*       2 */
   21952, /*       1 */
   32768, /*       1 */
   35311, /*       1 */
   43256, /*       2 */
   48914, /*       1 */
   63504, /*       8 */
   65536, /*       0 */
   92794, /*       1 */
  107602, /*       1 */
  131832, /*       7 */
  156920, /*       1 */
  262144, /*       1 */
  374608, /*       1 */
  507976, /*      10 */
  524288, /*       0 */
6eaca76e
 1048576,
ebf10d4a
 2097152,
 4194304,
 8388608,
34e79a80
  /* MAX_ALLOCATION is 184549376 but that's really not need here */
0281fb4d
 };
 
 #else
 
5684130b
 static const unsigned int fragsz[] = {
8a88afcf
 /* SIZE,        MAX */
       4, /*  576046 */
       7, /*  205452 */
       8, /*    2448 */
       9, /*    1633 */
      11, /*    2740 */
      12, /*    6315 */
      13, /*    8821 */
      15, /*   15903 */
      16, /*   31401 */
      17, /*   28027 */
      19, /*  136365 */
      20, /*   95662 */
      21, /*  176094 */
      23, /*   54138 */
      24, /*  156993 */
      25, /*   39393 */
      28, /*   16340 */
      29, /*    9807 */
      30, /*    5132 */
      31, /*  176283 */
      32, /*  484214 */
      33, /*  129187 */
      37, /*    1163 */
      40, /*    3311 */
      41, /*    1513 */
      48, /*    3930 */
      49, /*    1018 */
      56, /*    2303 */
      58, /*   13518 */
      59, /*    4709 */
      60, /*   13577 */
      61, /*    3093 */
      62, /*   10407 */
      63, /*    3973 */
      64, /*   26914 */
      65, /*    2963 */
      73, /*    2314 */
      81, /*    2038 */
      85, /*    1306 */
      88, /*    1395 */
      93, /*     885 */
      96, /*     878 */
     104, /*    3746 */
     108, /*     685 */
     113, /*    2940 */
     115, /*    3625 */
     116, /*    3827 */
     117, /*    2517 */
     119, /*    4260 */
     120, /*   17485 */
     121, /*    1945 */
     128, /*    2653 */
     131, /*    2304 */
     136, /*    1090 */
     143, /*   10787 */
     148, /*    1292 */
     152, /*    3494 */
     153, /*   11788 */
     168, /*     505 */
     176, /*     652 */
     200, /*     350 */
     216, /*     312 */
     232, /*     402 */
     248, /*     495 */
     256, /*     140 */
     284, /*     439 */
     309, /*     817 */
     452, /*      57 */
     512, /*       3 */
     784, /*      14 */
    1024, /*       2 */
    1028, /*    3191 */
    1032, /*    7777 */
    2048, /*       5 */
    4096, /*       3 */
    5128, /*       5 */
    8192, /*       3 */
   11264, /*       5 */
   11268, /*     238 */
   11272, /*     243 */
   16384, /*       1 */
   17657, /*       1 */
   21632, /*       2 */
   23188, /*       2 */
   24458, /*       1 */
   32768, /*       1 */
   46398, /*       1 */
   53804, /*       1 */
   63504, /*       7 */
   65536, /*       1 */
  131072, /*       0 */
  131080, /*       7 */
  131544, /*       2 */
  156920, /*       1 */
  187304, /*       1 */
  253988, /*      10 */
  262144, /*       0 */
6eaca76e
 1048576,
ebf10d4a
 2097152,
 4194304,
 8388608,
0281fb4d
 };
 #endif
 #define FRAGSBITS (sizeof(fragsz)/sizeof(fragsz[0]))
 
 struct MPMAP {
   struct MPMAP *next;
   unsigned int size;
   unsigned int usize;
 };
 
 struct MP {
   unsigned int psize;
   struct FRAG *avail[FRAGSBITS];
630d47cb
   union {
       struct MPMAP mpm;
       uint64_t dummy_align;
   } u;
0281fb4d
 };
e21657df
 
d068119a
 /* alignment of fake handled in the code! */
 struct alloced {
     uint8_t padding;
     uint8_t sbits;
     uint8_t fake;
 };
 
e21657df
 struct FRAG {
261e29da
 #ifdef CL_DEBUG
d068119a
   uint16_t magic;
261e29da
 #endif
b26d0ef3
   union {
d068119a
       struct alloced a;
       struct unaligned_ptr next;
b26d0ef3
   } u;
e21657df
 };
d068119a
 #define FRAG_OVERHEAD (offsetof(struct FRAG, u.a.fake))
e21657df
 
 static unsigned int align_to_pagesize(struct MP *mp, unsigned int size) {
   return (size / mp->psize + (size % mp->psize != 0)) * mp->psize;
 }
 
 static unsigned int to_bits(unsigned int size) {
   unsigned int i;
948644e6
   for(i=0; i<FRAGSBITS; i++)
     if(fragsz[i] >= size) return i;
946bd266
   return FRAGSBITS;
e21657df
 }
d068119a
 
e21657df
 static unsigned int from_bits(unsigned int bits) {
0281fb4d
   if (bits >= FRAGSBITS) return 0;
948644e6
   return fragsz[bits];
e21657df
 }
 
d068119a
 static inline unsigned int alignof(unsigned int size)
 {
     /* conservative estimate of alignment.
      * A struct that needs alignment of 'align' is padded by the compiler
      * so that sizeof(struct)%align == 0 
      * (otherwise you wouldn't be able to use it in an array)
      * Also align = 2^n.
      * Largest alignment we need is 8 bytes (ptr/int64), since we don't use long
      * double or __aligned attribute.
      * This conservatively estimates that size 32 needs alignment of 8 (even if it might only
      * need an alignment of 4).
      */
     switch (size%8) {
 	case 0:
 	    return 8;
 	case 2:
5f12eacb
 	case 6:
d068119a
 	    return 2;
 	case 4:
 	    return 4;
 	default:
 	    return 1;
     }
 }
 
 static inline size_t alignto(size_t p, size_t size)
 {
     /* size is power of 2 */
     return (p+size-1)&(~(size-1));
 }
 
47d40feb
 struct MP *mpool_create() {
   struct MP mp, *mpool_p;
948644e6
   unsigned int sz;
e21657df
   memset(&mp, 0, sizeof(mp));
86d59b24
   mp.psize = cli_getpagesize();
948644e6
   sz = align_to_pagesize(&mp, MIN_FRAGSIZE);
d068119a
   mp.u.mpm.usize = sizeof(struct MPMAP);
   mp.u.mpm.size = sz - sizeof(mp);
4743d54f
 #ifndef _WIN32
47d40feb
   if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
4743d54f
 #else
   if(!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
 #endif
e21657df
     return NULL;
d068119a
   if (FRAGSBITS > 255) {
       cli_errmsg("At most 255 frags possible!\n");
       return NULL;
   }
   if (fragsz[0] < sizeof(void*)) {
       cli_errmsg("fragsz[0] too small!\n");
       return NULL;
   }
1b802d3c
 #ifdef CL_DEBUG
   memset(mpool_p, ALLOCPOISON, sz);
 #endif
47d40feb
   memcpy(mpool_p, &mp, sizeof(mp));
630d47cb
   spam("Map created @%p->%p - size %u out of %u - voidptr=%u\n", mpool_p, (char *)mpool_p + mp.u.mpm.size, mp.u.mpm.usize, mp.u.mpm.size, SIZEOF_VOID_P);
47d40feb
   return mpool_p;
e21657df
 }
 
47d40feb
 void mpool_destroy(struct MP *mp) {
630d47cb
   struct MPMAP *mpm_next = mp->u.mpm.next, *mpm;
1b802d3c
   unsigned int mpmsize;
 
e21657df
   while((mpm = mpm_next)) {
1b802d3c
     mpmsize = mpm->size;
e21657df
     mpm_next = mpm->next;
1b802d3c
 #ifdef CL_DEBUG
     memset(mpm, FREEPOISON, mpmsize);
 #endif
4743d54f
 #ifndef _WIN32
1b802d3c
     munmap((void *)mpm, mpmsize);
4743d54f
 #else
     VirtualFree(mpm, 0, MEM_RELEASE);
 #endif
e21657df
   }
630d47cb
   mpmsize = mp->u.mpm.size;
1b802d3c
 #ifdef CL_DEBUG
d068119a
   memset(mp, FREEPOISON, mpmsize + sizeof(*mp));
1b802d3c
 #endif
4743d54f
 #ifndef _WIN32
d068119a
   munmap((void *)mp, mpmsize + sizeof(*mp));
4743d54f
 #else
   VirtualFree(mp, 0, MEM_RELEASE);
 #endif
34e79a80
   spam("Map destroyed @%p\n", mp);
e21657df
 }
 
47d40feb
 void mpool_flush(struct MP *mp) {
34e79a80
     size_t used = 0, mused;
630d47cb
     struct MPMAP *mpm_next = mp->u.mpm.next, *mpm;
1b802d3c
 
34e79a80
 #ifdef EXIT_ON_FLUSH
     exit(0);
 #endif
 
     while((mpm = mpm_next)) {
 	mpm_next = mpm->next;
 	mused = align_to_pagesize(mp, mpm->usize);
 	if(mused < mpm->size) {
1b802d3c
 #ifdef CL_DEBUG
34e79a80
 	    memset((char *)mpm + mused, FREEPOISON, mpm->size - mused);
1b802d3c
 #endif
4743d54f
 #ifndef _WIN32
34e79a80
 	    munmap((char *)mpm + mused, mpm->size - mused);
4743d54f
 #else
 	    VirtualFree((char *)mpm + mused, mpm->size - mused, MEM_DECOMMIT);
 #endif
34e79a80
 	    mpm->size = mused;
 	}
 	used += mpm->size;
     }
 
d068119a
     mused = align_to_pagesize(mp, mp->u.mpm.usize + sizeof(*mp));
     if (mused < mp->u.mpm.size + sizeof(*mp)) {
1b802d3c
 #ifdef CL_DEBUG
d068119a
 	memset((char *)mp + mused, FREEPOISON, mp->u.mpm.size + sizeof(*mp) - mused);
1b802d3c
 #endif
4743d54f
 #ifndef _WIN32
d068119a
 	munmap((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused);
4743d54f
 #else
d068119a
 	VirtualFree((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused, MEM_DECOMMIT);
4743d54f
 #endif
d068119a
 	mp->u.mpm.size = mused - sizeof(*mp);
34e79a80
     }
630d47cb
     used += mp->u.mpm.size;
34e79a80
     spam("Map flushed @%p, in use: %lu\n", mp, used);
deb30312
 }
 
47d40feb
 int mpool_getstats(const struct cl_engine *eng, size_t *used, size_t *total)
deb30312
 {
1b802d3c
   size_t sum_used = 0, sum_total = 0;
   const struct MPMAP *mpm;
   const mpool_t *mp;
   
   /* checking refcount is not necessary, but safer */
   if (!eng || !eng->refcount)
     return -1;
   mp = eng->mempool;
   if (!mp)
     return -1;
630d47cb
   for(mpm = &mp->u.mpm; mpm; mpm = mpm->next) {
1b802d3c
     sum_used += mpm->usize;
     sum_total += mpm->size;
   }
   *used = sum_used;
   *total = sum_total;
   return 0;
e21657df
 }
 
d068119a
 static inline unsigned align_increase(unsigned size, unsigned a)
 {
     /* we must pad with at most a-1 bytes to align start of struct */
     return size + a - 1;
 }
 
 static void* allocate_aligned(struct MPMAP *mpm, unsigned long size, unsigned align, const char *dbg)
 {
     /* We could always align the size to maxalign (8), however that wastes
      * space.
      * So just align the start of each allocation as needed, and then see in
      * which sbits bin we fit into.
      * Since we are no longer allocating in multiple of 8, we must always
      * align the start of each allocation!
      *| end of previous allocation | padding | FRAG_OVERHEAD | ptr_aligned |*/
     unsigned p = mpm->usize + FRAG_OVERHEAD;
     unsigned p_aligned = alignto(p, align);
     struct FRAG *f = (struct FRAG*)((char*)mpm + p_aligned - FRAG_OVERHEAD);
     unsigned realneed = p_aligned + size - mpm->usize;
     unsigned sbits = to_bits(realneed);
     unsigned needed = from_bits(sbits);
 #ifdef CL_DEBUG
     assert(p_aligned + size <= mpm->size);
 #endif
     f->u.a.sbits = sbits;
     f->u.a.padding = p_aligned - p;
 
     mpm->usize += needed;
 #ifdef CL_DEBUG
     assert(mpm->usize <= mpm->size);
 #endif
     spam("malloc @%p size %u (%s) origsize %u overhead %u\n", f, realneed, dbg, size, needed - size);
 #ifdef CL_DEBUG
     f->magic = MPOOLMAGIC;
     memset(&f->u.a.fake, ALLOCPOISON, size);
 #endif
     return &f->u.a.fake;
 }
 
47d40feb
 void *mpool_malloc(struct MP *mp, size_t size) {
d068119a
   unsigned align = alignof(size);
   unsigned int i, needed = align_increase(size+FRAG_OVERHEAD, align);
e21657df
   const unsigned int sbits = to_bits(needed);
   struct FRAG *f = NULL;
630d47cb
   struct MPMAP *mpm = &mp->u.mpm;
e21657df
 
948644e6
   /*  check_all(mp); */
946bd266
   if (!size || sbits == FRAGSBITS) {
47d40feb
     cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
946bd266
     return NULL;
   }
e21657df
 
   /* Case 1: We have a free'd frag */
0281fb4d
   if((f = mp->avail[sbits])) {
d068119a
     struct FRAG *fold = f;
     mp->avail[sbits] = f->u.next.ptr;
     /* we always have enough space for this, align_increase ensured that */
5f12eacb
     f = (struct FRAG*)(alignto((unsigned long)f + FRAG_OVERHEAD, align)-FRAG_OVERHEAD);
d068119a
     f->u.a.sbits = sbits;
     f->u.a.padding = (char*)f - (char*)fold;
ad0fd728
 #ifdef CL_DEBUG
d068119a
     f->magic = MPOOLMAGIC;
     memset(&f->u.a.fake, ALLOCPOISON, size);
ad0fd728
 #endif
d068119a
     spam("malloc @%p size %u (freed) origsize %u overhead %u\n", f, f->u.a.padding + FRAG_OVERHEAD + size, size, needed - size);
     return &f->u.a.fake;
e21657df
   }
 
946bd266
   if (!(needed = from_bits(sbits))) {
47d40feb
     cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
946bd266
     return NULL;
   }
e21657df
 
   /* Case 2: We have nuff room available for this frag already */
   while(mpm) {
d068119a
     if(mpm->size - mpm->usize >= needed)
 	return allocate_aligned(mpm, size, align, "hole");
e21657df
     mpm = mpm->next;
   }
 
   /* Case 3: We allocate more */
d068119a
   if (needed + sizeof(*mpm) > MIN_FRAGSIZE)
   i = align_to_pagesize(mp, needed + sizeof(*mpm));
e21657df
   else
   i = align_to_pagesize(mp, MIN_FRAGSIZE);
4743d54f
 
 #ifndef _WIN32
946bd266
   if ((mpm = (struct MPMAP *)mmap(NULL, i, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) {
4743d54f
 #else
   if (!(mpm = (struct MPMAP *)VirtualAlloc(NULL, i, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))) {
 #endif
47d40feb
     cli_errmsg("mpool_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int)i);
e21657df
     spam("failed to alloc %u bytes (%u requested)\n", i, size);
     return NULL;
   }
1b802d3c
 #ifdef CL_DEBUG
   memset(mpm, ALLOCPOISON, i);
 #endif
e21657df
   mpm->size = i;
d068119a
   mpm->usize = sizeof(*mpm);
630d47cb
   mpm->next = mp->u.mpm.next;
   mp->u.mpm.next = mpm;
d068119a
   return allocate_aligned(mpm, size, align, "new map");
 }
 
 static void *allocbase_fromfrag(struct FRAG *f)
 {
7866b37c
 #ifdef CL_DEBUG
d068119a
     assert(f->u.a.padding < 8);
7866b37c
 #endif
d068119a
     return (char*)f - f->u.a.padding;
e21657df
 }
 
47d40feb
 void mpool_free(struct MP *mp, void *ptr) {
fd856af4
   struct FRAG *f = (struct FRAG *)((char *)ptr - FRAG_OVERHEAD);
b26d0ef3
   unsigned int sbits;
e21657df
   if (!ptr) return;
 
7866b37c
 #ifdef CL_DEBUG
47d40feb
   assert(f->magic == MPOOLMAGIC && "Attempt to mpool_free a pointer we did not allocate!");
7866b37c
 #endif
 
34e79a80
   spam("free @%p\n", f);
d068119a
   sbits = f->u.a.sbits;
   f = allocbase_fromfrag(f);
 #ifdef CL_DEBUG
   memset(f, FREEPOISON, from_bits(sbits));
 #endif
 
   f->u.next.ptr = mp->avail[sbits];
   mp->avail[sbits] = f;
e21657df
 }
 
47d40feb
 void *mpool_calloc(struct MP *mp, size_t nmemb, size_t size) {
e21657df
   unsigned int needed = nmemb*size;
   void *ptr;
 
   if(!needed) return NULL;
47d40feb
   if((ptr = mpool_malloc(mp, needed)))
e21657df
     memset(ptr, 0, needed);
   return ptr;
 }
 
47d40feb
 void *mpool_realloc(struct MP *mp, void *ptr, size_t size) {
fd856af4
   struct FRAG *f = (struct FRAG *)((char *)ptr - FRAG_OVERHEAD);
1b802d3c
   unsigned int csize;
e21657df
   void *new_ptr;
47d40feb
   if (!ptr) return mpool_malloc(mp, size);
e21657df
 
d068119a
   if(!size || !(csize = from_bits(f->u.a.sbits))) {
47d40feb
     cli_errmsg("mpool_realloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
946bd266
     return NULL;
   }
d068119a
   csize -= FRAG_OVERHEAD + f->u.a.padding;
   if (csize >= size && (!f->u.a.sbits || from_bits(f->u.a.sbits-1)-FRAG_OVERHEAD-f->u.a.padding < size)) {
34e79a80
     spam("free @%p\n", f);
d068119a
     spam("malloc @%p size %u (self) origsize %u overhead %u\n", f, size + FRAG_OVERHEAD + f->u.a.padding, size, csize-size+FRAG_OVERHEAD+f->u.a.padding);
b26d0ef3
     return ptr;
34e79a80
   }
47d40feb
   if (!(new_ptr = mpool_malloc(mp, size)))
e21657df
     return NULL;
46826baf
   memcpy(new_ptr, ptr, csize <= size ? csize : size);
47d40feb
   mpool_free(mp, ptr);
e21657df
   return new_ptr;
 }
 
47d40feb
 void *mpool_realloc2(struct MP *mp, void *ptr, size_t size) {
34e79a80
     void *new_ptr = mpool_realloc(mp, ptr, size);
     if(new_ptr)
 	return new_ptr;
47d40feb
     mpool_free(mp, ptr);
0281fb4d
     return NULL;
e21657df
 }
 
12c6a97e
 unsigned char *cli_mpool_hex2str(mpool_t *mp, const char *hex) {
eaf2aebd
     unsigned char *str;
     size_t len = strlen((const char*)hex);
 
     if (len&1) {
025243f6
 	cli_errmsg("cli_hex2str(): Malformed hexstring: %s (length: %u)\n", hex, (unsigned)len);
eaf2aebd
 	return NULL;
     }
 
     str = mpool_malloc(mp, (len/2) + 1);
e4a0f2c9
     if (cli_hex2str_to(hex, (char*)str, len) == -1) {
eaf2aebd
 	mpool_free(mp, str);
 	return NULL;
     }
     str[len/2] = '\0';
     return str;
ad0fd728
 }
 
47d40feb
 char *cli_mpool_strdup(mpool_t *mp, const char *s) {
d6e1ef16
   char *alloc;
   unsigned int strsz;
 
   if(s == NULL) {
47d40feb
     cli_errmsg("cli_mpool_strdup(): s == NULL. Please report to http://bugs.clamav.net\n");
d6e1ef16
     return NULL;
   }
 
   strsz = strlen(s) + 1;
47d40feb
   alloc = mpool_malloc(mp, strsz);
d6e1ef16
   if(!alloc)
47d40feb
     cli_errmsg("cli_mpool_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int) strsz);
d6e1ef16
   else
     memcpy(alloc, s, strsz);
   return alloc;
 }
 
47d40feb
 char *cli_mpool_virname(mpool_t *mp, const char *virname, unsigned int official) {
d6e1ef16
   char *newname, *pt;
   if(!virname)
     return NULL;
 
eaf2aebd
   if((pt = strchr(virname, ' ')))
       if((pt = strstr(pt, " (Clam)")))
 	  *pt='\0';
d6e1ef16
 
   if(!virname[0]) {
     cli_errmsg("cli_virname: Empty virus name\n");
     return NULL;
   }
 
   if(official)
47d40feb
     return cli_mpool_strdup(mp, virname);
d6e1ef16
 
47d40feb
   newname = (char *)mpool_malloc(mp, strlen(virname) + 11 + 1);
d6e1ef16
   if(!newname) {
     cli_errmsg("cli_virname: Can't allocate memory for newname\n");
     return NULL;
   }
   sprintf(newname, "%s.UNOFFICIAL", virname);
   return newname;
 }
 
 
47d40feb
 uint16_t *cli_mpool_hex2ui(mpool_t *mp, const char *hex) {
38e881e3
   uint16_t *str;
   unsigned int len;
   
   len = strlen(hex);
 
   if(len % 2 != 0) {
01a11a38
     cli_errmsg("cli_mpool_hex2ui(): Malformed hexstring: %s (length: %u)\n", hex, len);
38e881e3
     return NULL;
   }
 
47d40feb
   str = mpool_calloc(mp, (len / 2) + 1, sizeof(uint16_t));
38e881e3
   if(!str)
     return NULL;
 
   if(cli_realhex2ui(hex, str, len))
     return str;
     
47d40feb
   mpool_free(mp, str);
38e881e3
   return NULL;
 }
 
 
946bd266
 #ifdef DEBUGMPOOL
47d40feb
 void mpool_stats(struct MP *mp) {
946bd266
   unsigned int i=0, ta=0, tu=0;
630d47cb
   struct MPMAP *mpm = &mp->u.mpm;
946bd266
 
   cli_warnmsg("MEMORY POOL STATISTICS\n map  \tsize\tused\t%\n");
   while(mpm) {
     cli_warnmsg("- %u\t%u\t%u\t%f%%\n", i, mpm->size, mpm->usize, (float)mpm->usize/(float)mpm->size*100);
     ta+=mpm->size;
     tu+=mpm->usize;
     i++;
     mpm = mpm->next;
   }
   cli_warnmsg("MEMORY POOL SUMMARY\nMaps: %u\nTotal: %u\nUsed: %u (%f%%)\n", i, ta, tu, (float)tu/(float)ta*100);
 }
 
 void check_all(struct MP *mp) {
630d47cb
   struct MPMAP *mpm = &mp->u.mpm;
946bd266
   while(mpm) {
     volatile unsigned char *c = (unsigned char *)mpm;
     unsigned int len = mpm->size;
     spam("checking object %p - size %u\n", mpm, len);
     while (len--) {
       c[len];
     }
     mpm=mpm->next;
   }
 }
 #endif /* DEBUGMPOOL */
 
ad0fd728
 
db43492c
 #else
 /* dummy definitions to make Solaris linker happy.
  * these symbols are declared in libclamav.map */
47d40feb
 void mpool_free() {}
 void mpool_create() {}
 void mpool_destroy() {}
 void mpool_getstats() {}
ad0fd728
 
e21657df
 #endif /* USE_MPOOL */
db43492c