libclamav/mpool.c
e21657df
 /*
14e2247b
  *  Copyright (C) 2015-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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>
 
60d8d2c3
 #include "clamav.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
cd94be7a
 static inline void spam(const char *fmt, ...) { UNUSEDPARAM(fmt); }
e21657df
 #endif
 
 #include "mpool.h"
 
80871017
 #undef CL_DEBUG /* bb#2222 */
 
18f620f2
 #ifdef C_HPUX
 #define MIN_FRAGSIZE 1048576	/* Goes with LDFLAGS=-Wl,+pd,1M */
 #else
34e79a80
 #define MIN_FRAGSIZE 262144
18f620f2
 #endif
e21657df
 
0281fb4d
 #if SIZEOF_VOID_P==8
 static const unsigned int fragsz[] = {
697b276e
     8,
     11,
     13,
     16,
     17,
     19,
     20,
     21,
     22,
     23,
     24,
     25,
     26,
     27,
     28,
     29,
     30,
     31,
     32,
     33,
     37,
     40,
     41,
     48,
     56,
     72,
     74,
     75,
     76,
     78,
     79,
     80,
     81,
     101,
     104,
     109,
     113,
     116,
     120,
     128,
     131,
     143,
     151,
     152,
     153,
     196,
     256,
     360,
     403,
     404,
     432,
     486,
     514,
     548,
     578,
     604,
     633,
     697,
     743,
     784,
     839,
    1176,
    1536,
    1666,
    2056,
    2168,
    2392,
    2985,
    3221,
    3433,
    3753,
    3832,
    4104,
    4280,
    4696,
    4952,
    5256,
    5826,
    6264,
    7176,
    8440,
    9096,
   16392,
   32780,
   50961,
   63504,
   65558,
  101912,
  131088,
  262144,
  507976,
  524296,
 1048584,
ebf10d4a
 2097152,
 4194304,
 8388608,
2beb84a1
 16777216,
 33554432,
 67108864,
 134217728,
34e79a80
  /* MAX_ALLOCATION is 184549376 but that's really not need here */
2beb84a1
  /* ^^ This MAX_ALLOCATION warning for Mac OS should now be fixed */
0281fb4d
 };
 
 #else
 
5684130b
 static const unsigned int fragsz[] = {
d4c6e1d6
     4,
     5,
     8,
     9,
     11,
     12,
     13,
     14,
     15,
     16,
     17,
     19,
     20,
     21,
     22,
     23,
     24,
     25,
     26,
     27,
     28,
     29,
     30,
     31,
     32,
     33,
     35,
     36,
     37,
     39,
     40,
     41,
     44,
     48,
     49,
     52,
     53,
     56,
     58,
     59,
     60,
     61,
     62,
     63,
     64,
     65,
     68,
     69,
     72,
     73,
     77,
     80,
     81,
     83,
     85,
     88,
     89,
     93,
     96,
     99,
     101,
     103,
     104,
     105,
     108,
     112,
     113,
     115,
     116,
     117,
     119,
     120,
     121,
     124,
     128,
     129,
     131,
     133,
     136,
     137,
     141,
     143,
     145,
     148,
     151,
     152,
     153,
     160,
     168,
     173,
     176,
     184,
     194,
     200,
     208,
     216,
     224,
     229,
     232,
     241,
     244,
     248,
     256,
     257,
     264,
     274,
     280,
     293,
     296,
     304,
     307,
     312,
     326,
     344,
     354,
     372,
     396,
     403,
     418,
     456,
     485,
     514,
     546,
     581,
     608,
     646,
     693,
     740,
     776,
     805,
     828,
     902,
     964,
     1028,
     1032,
     1136,
     1238,
     1314,
     1420,
     1501,
     1668,
     1720,
     1832,
     1940,
     2048,
     2119,
     2264,
     2584,
     2724,
     2994,
     3336,
     3428,
     3828,
     4104,
     4471,
     4836,
     5044,
     5176,
     5912,
     6227,
     6792,
     7732,
     8192,
     11272,
     12500,
     16384,
     32768,
     63500,
     65536,
     131080,
     253988,
     262148,
     524292,
     1048576,
     2097152,
     4194304,
     8388608,
2beb84a1
    16777216,
    33554432,
    67108864,
   134217728,
0281fb4d
 };
 #endif
cd7c9a4f
 
0281fb4d
 #define FRAGSBITS (sizeof(fragsz)/sizeof(fragsz[0]))
 
 struct MPMAP {
   struct MPMAP *next;
110714bb
   size_t size;
   size_t usize;
0281fb4d
 };
 
 struct MP {
110714bb
   size_t psize;
0281fb4d
   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
 
110714bb
 static size_t align_to_pagesize(struct MP *mp, size_t size) {
e21657df
   return (size / mp->psize + (size % mp->psize != 0)) * mp->psize;
 }
 
110714bb
 static unsigned int to_bits(size_t size) {
e21657df
   unsigned int i;
948644e6
   for(i=0; i<FRAGSBITS; i++)
     if(fragsz[i] >= size) return i;
946bd266
   return FRAGSBITS;
e21657df
 }
d068119a
 
110714bb
 static size_t from_bits(unsigned int bits) {
0281fb4d
   if (bits >= FRAGSBITS) return 0;
948644e6
   return fragsz[bits];
e21657df
 }
 
110714bb
 static inline unsigned int alignof(size_t size)
d068119a
 {
     /* 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;
110714bb
   size_t 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);
   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;
   }
f526f0b2
 #ifndef _WIN32
   if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
 #else
   if(!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
 #endif
     return NULL;
1b802d3c
 #ifdef CL_DEBUG
   memset(mpool_p, ALLOCPOISON, sz);
 #endif
47d40feb
   memcpy(mpool_p, &mp, sizeof(mp));
110714bb
   spam("Map created @%p->%p - size %lu out of %lu - voidptr=%lu\n", mpool_p, (char *)mpool_p + mp.u.mpm.size, (unsigned long)mp.u.mpm.usize, (unsigned long)mp.u.mpm.size, (unsigned long)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;
110714bb
   size_t mpmsize;
1b802d3c
 
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;
7cbc72d3
     cli_dbgmsg("pool memory used: %.3f MB\n", used/(1024*1024.0));
110714bb
     spam("Map flushed @%p, in use: %lu\n", mp, (unsigned long)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
 }
 
110714bb
 static inline size_t align_increase(size_t size, size_t a)
d068119a
 {
     /* we must pad with at most a-1 bytes to align start of struct */
     return size + a - 1;
 }
 
110714bb
 static void* allocate_aligned(struct MPMAP *mpm, size_t size, unsigned align, const char *dbg)
d068119a
 {
     /* 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;
110714bb
     unsigned int sbits = to_bits(realneed);
     size_t needed = from_bits(sbits);
d068119a
 #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
110714bb
     spam("malloc @%p size %lu (%s) origsize %lu overhead %lu\n", f, (unsigned long)realneed, dbg, (unsigned long)size, (unsigned long)(needed - size));
d068119a
 #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) {
110714bb
   size_t align = alignof(size);
   size_t 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) {
964a1e73
     cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long) 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 */
ac20e91b
 #ifdef _WIN64
b6768907
     f = (struct FRAG*)(alignto((unsigned long long)f + FRAG_OVERHEAD, align)-FRAG_OVERHEAD);
ac20e91b
 #else
b6768907
     f = (struct FRAG*)(alignto((unsigned long)f + FRAG_OVERHEAD, align)-FRAG_OVERHEAD);
ac20e91b
 #endif
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
110714bb
     spam("malloc @%p size %lu (freed) origsize %lu overhead %lu\n", f, (unsigned long)(f->u.a.padding + FRAG_OVERHEAD + size), (unsigned long)size, (unsigned long)(needed - size));
d068119a
     return &f->u.a.fake;
e21657df
   }
 
946bd266
   if (!(needed = from_bits(sbits))) {
964a1e73
     cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long) 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
110714bb
     cli_errmsg("mpool_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long)i);
     spam("failed to alloc %lu bytes (%lu requested)\n", (unsigned long)i, (unsigned long)size);
e21657df
     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) {
110714bb
   size_t needed = nmemb*size;
e21657df
   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);
110714bb
   size_t csize;
e21657df
   void *new_ptr;
47d40feb
   if (!ptr) return mpool_malloc(mp, size);
e21657df
 
d068119a
   if(!size || !(csize = from_bits(f->u.a.sbits))) {
964a1e73
     cli_errmsg("mpool_realloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long) 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);
110714bb
     spam("malloc @%p size %lu (self) origsize %lu overhead %lu\n", f, (unsigned long)(size + FRAG_OVERHEAD + f->u.a.padding), (unsigned long)size, (unsigned long)(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
 }
 
7b1f1aaf
 char *cli_mpool_hex2str(mpool_t *mp, const char *hex) {
     char *str;
eaf2aebd
     size_t len = strlen((const char*)hex);
 
     if (len&1) {
5fc6e404
 	cli_errmsg("cli_hex2str(): Malformed hexstring: %s (length: %lu)\n", hex, (unsigned long)len);
eaf2aebd
 	return NULL;
     }
 
     str = mpool_malloc(mp, (len/2) + 1);
e522909e
     if (str == NULL) { /* oops, we have a memory pool allocation failure */
5fc6e404
 	cli_errmsg("cli_mpool_hex2str(): Can't allocate memory (%lu bytes).\n", (unsigned long)(len/2 + 1));
e522909e
 	return NULL;
     }
7b1f1aaf
     if (cli_hex2str_to(hex, 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;
110714bb
   size_t strsz;
d6e1ef16
 
   if(s == NULL) {
964a1e73
     cli_errmsg("cli_mpool_strdup(): s == NULL. Please report to https://bugzilla.clamav.net\n");
d6e1ef16
     return NULL;
   }
 
   strsz = strlen(s) + 1;
47d40feb
   alloc = mpool_malloc(mp, strsz);
d6e1ef16
   if(!alloc)
110714bb
     cli_errmsg("cli_mpool_strdup(): Can't allocate memory (%lu bytes).\n", (unsigned long) strsz);
d6e1ef16
   else
     memcpy(alloc, s, strsz);
   return alloc;
 }
 
67f8441d
 char *cli_mpool_strndup(mpool_t *mp, const char *s, size_t n) {
   char *alloc;
   size_t strsz;
 
   if(s == NULL) {
964a1e73
     cli_errmsg("cli_mpool_strndup(): s == NULL. Please report to https://bugzilla.clamav.net\n");
67f8441d
     return NULL;
   }
 
47a544dc
   strsz = cli_strnlen(s, n) + 1;
67f8441d
   alloc = mpool_malloc(mp, strsz);
   if(!alloc)
     cli_errmsg("cli_mpool_strndup(): Can't allocate memory (%lu bytes).\n", (unsigned long) strsz);
   else
     memcpy(alloc, s, strsz-1);
   alloc[strsz-1] = '\0';
   return alloc;
 }
 
4f798ac6
 /* #define EXPAND_PUA */
47d40feb
 char *cli_mpool_virname(mpool_t *mp, const char *virname, unsigned int official) {
d6e1ef16
   char *newname, *pt;
4f798ac6
 #ifdef EXPAND_PUA
   char buf[1024];
 #endif
 
d6e1ef16
   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;
   }
 
4f798ac6
 #ifdef EXPAND_PUA
     if(!strncmp(virname, "PUA.", 4)) {
 	snprintf(buf, sizeof(buf), "Possibly-Unwanted-Application(www.clamav.net/support/pua).%s", virname + 4);
 	buf[sizeof(buf)-1] = '\0';
 	virname = buf;
     }
 #endif
d6e1ef16
   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;
110714bb
   size_t len;
38e881e3
   
   len = strlen(hex);
 
   if(len % 2 != 0) {
110714bb
     cli_errmsg("cli_mpool_hex2ui(): Malformed hexstring: %s (length: %lu)\n", hex, (unsigned long)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) {
110714bb
   size_t 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) {
110714bb
     cli_warnmsg("- %lu\t%lu\t%lu\t%f%%\n", (unsigned long)i, (unsigned long)(mpm->size), (unsigned long)(mpm->usize), (float)mpm->usize/(float)mpm->size*100);
946bd266
     ta+=mpm->size;
     tu+=mpm->usize;
     i++;
     mpm = mpm->next;
   }
110714bb
   cli_warnmsg("MEMORY POOL SUMMARY\nMaps: %lu\nTotal: %lu\nUsed: %lu (%f%%)\n", (unsigned long)i, (unsigned long)ta, (unsigned long)tu, (float)tu/(float)ta*100);
946bd266
 }
 
 void check_all(struct MP *mp) {
630d47cb
   struct MPMAP *mpm = &mp->u.mpm;
946bd266
   while(mpm) {
     volatile unsigned char *c = (unsigned char *)mpm;
110714bb
     size_t len = mpm->size;
     spam("checking object %p - size %lu\n", mpm, (unsigned long)len);
946bd266
     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() {}
8a6c2921
 void mpool_calloc() {}
ad0fd728
 
e21657df
 #endif /* USE_MPOOL */
db43492c
 
110714bb