1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2008-2013 Sourcefire, Inc.
4 *
5 * Authors: aCaB <acab@clamav.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 /* a naive pool allocator */
23
24 #if HAVE_CONFIG_H
25 #include "clamav-config.h"
26 #endif
27
28 #ifdef USE_MPOOL
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H)
40 #include <sys/mman.h>
41 #endif
42 #include <stddef.h>
43
44 #include "clamav.h"
45 #include "others.h"
46 #include "str.h"
47 #include "readdb.h"
48
49 /*#define CL_DEBUG*/
50 #ifdef CL_DEBUG
51 #include <assert.h>
52 #define MPOOLMAGIC 0xadde
53 #define ALLOCPOISON 0x5a
54 #define FREEPOISON 0xde
55 #endif
56
57 /*#define DEBUGMPOOL
58 #define EXIT_ON_FLUSH*/
59 #ifdef DEBUGMPOOL
60 #define spam(...) cli_warnmsg(__VA_ARGS__)
61 #else
spam(const char * fmt,...)62 static inline void spam(const char *fmt, ...)
63 {
64 UNUSEDPARAM(fmt);
65 }
66 #endif
67
68 #include "mpool.h"
69
70 #undef CL_DEBUG /* bb#2222 */
71
72 #ifdef C_HPUX
73 #define MIN_FRAGSIZE 1048576 /* Goes with LDFLAGS=-Wl,+pd,1M */
74 #else
75 #define MIN_FRAGSIZE 262144
76 #endif
77
78 #if SIZEOF_VOID_P == 8
79 static const unsigned int fragsz[] = {
80 8,
81 11,
82 13,
83 16,
84 17,
85 19,
86 20,
87 21,
88 22,
89 23,
90 24,
91 25,
92 26,
93 27,
94 28,
95 29,
96 30,
97 31,
98 32,
99 33,
100 37,
101 40,
102 41,
103 48,
104 56,
105 72,
106 74,
107 75,
108 76,
109 78,
110 79,
111 80,
112 81,
113 101,
114 104,
115 109,
116 113,
117 116,
118 120,
119 128,
120 131,
121 143,
122 151,
123 152,
124 153,
125 196,
126 256,
127 360,
128 403,
129 404,
130 432,
131 486,
132 514,
133 548,
134 578,
135 604,
136 633,
137 697,
138 743,
139 784,
140 839,
141 1176,
142 1536,
143 1666,
144 2056,
145 2168,
146 2392,
147 2985,
148 3221,
149 3433,
150 3753,
151 3832,
152 4104,
153 4280,
154 4696,
155 4952,
156 5256,
157 5826,
158 6264,
159 7176,
160 8440,
161 9096,
162 16392,
163 32780,
164 50961,
165 63504,
166 65558,
167 101912,
168 131088,
169 262144,
170 507976,
171 524296,
172 1048584,
173 2097152,
174 4194304,
175 8388608,
176 16777216,
177 33554432,
178 67108864,
179 134217728,
180 /* MAX_ALLOCATION is 184549376 but that's really not need here */
181 /* ^^ This MAX_ALLOCATION warning for Mac OS should now be fixed */
182 };
183
184 #else
185
186 static const unsigned int fragsz[] = {
187 4,
188 5,
189 8,
190 9,
191 11,
192 12,
193 13,
194 14,
195 15,
196 16,
197 17,
198 19,
199 20,
200 21,
201 22,
202 23,
203 24,
204 25,
205 26,
206 27,
207 28,
208 29,
209 30,
210 31,
211 32,
212 33,
213 35,
214 36,
215 37,
216 39,
217 40,
218 41,
219 44,
220 48,
221 49,
222 52,
223 53,
224 56,
225 58,
226 59,
227 60,
228 61,
229 62,
230 63,
231 64,
232 65,
233 68,
234 69,
235 72,
236 73,
237 77,
238 80,
239 81,
240 83,
241 85,
242 88,
243 89,
244 93,
245 96,
246 99,
247 101,
248 103,
249 104,
250 105,
251 108,
252 112,
253 113,
254 115,
255 116,
256 117,
257 119,
258 120,
259 121,
260 124,
261 128,
262 129,
263 131,
264 133,
265 136,
266 137,
267 141,
268 143,
269 145,
270 148,
271 151,
272 152,
273 153,
274 160,
275 168,
276 173,
277 176,
278 184,
279 194,
280 200,
281 208,
282 216,
283 224,
284 229,
285 232,
286 241,
287 244,
288 248,
289 256,
290 257,
291 264,
292 274,
293 280,
294 293,
295 296,
296 304,
297 307,
298 312,
299 326,
300 344,
301 354,
302 372,
303 396,
304 403,
305 418,
306 456,
307 485,
308 514,
309 546,
310 581,
311 608,
312 646,
313 693,
314 740,
315 776,
316 805,
317 828,
318 902,
319 964,
320 1028,
321 1032,
322 1136,
323 1238,
324 1314,
325 1420,
326 1501,
327 1668,
328 1720,
329 1832,
330 1940,
331 2048,
332 2119,
333 2264,
334 2584,
335 2724,
336 2994,
337 3336,
338 3428,
339 3828,
340 4104,
341 4471,
342 4836,
343 5044,
344 5176,
345 5912,
346 6227,
347 6792,
348 7732,
349 8192,
350 11272,
351 12500,
352 16384,
353 32768,
354 63500,
355 65536,
356 131080,
357 253988,
358 262148,
359 524292,
360 1048576,
361 2097152,
362 4194304,
363 8388608,
364 16777216,
365 33554432,
366 67108864,
367 134217728,
368 };
369 #endif
370
371 #define FRAGSBITS (sizeof(fragsz) / sizeof(fragsz[0]))
372
373 struct MPMAP {
374 struct MPMAP *next;
375 size_t size;
376 size_t usize;
377 };
378
379 struct MP {
380 size_t psize;
381 struct FRAG *avail[FRAGSBITS];
382 union {
383 struct MPMAP mpm;
384 uint64_t dummy_align;
385 } u;
386 };
387
388 /* alignment of fake handled in the code! */
389 struct alloced {
390 uint8_t padding;
391 uint8_t sbits;
392 uint8_t fake;
393 };
394
395 struct FRAG {
396 #ifdef CL_DEBUG
397 uint16_t magic;
398 #endif
399 union {
400 struct alloced a;
401 struct unaligned_ptr next;
402 } u;
403 };
404 #define FRAG_OVERHEAD (offsetof(struct FRAG, u.a.fake))
405
align_to_pagesize(struct MP * mp,size_t size)406 static size_t align_to_pagesize(struct MP *mp, size_t size)
407 {
408 return (size / mp->psize + (size % mp->psize != 0)) * mp->psize;
409 }
410
to_bits(size_t size)411 static unsigned int to_bits(size_t size)
412 {
413 unsigned int i;
414 for (i = 0; i < FRAGSBITS; i++)
415 if (fragsz[i] >= size) return i;
416 return FRAGSBITS;
417 }
418
from_bits(unsigned int bits)419 static size_t from_bits(unsigned int bits)
420 {
421 if (bits >= FRAGSBITS) return 0;
422 return fragsz[bits];
423 }
424
alignof(size_t size)425 static inline unsigned int alignof(size_t size)
426 {
427 /* conservative estimate of alignment.
428 * A struct that needs alignment of 'align' is padded by the compiler
429 * so that sizeof(struct)%align == 0
430 * (otherwise you wouldn't be able to use it in an array)
431 * Also align = 2^n.
432 * Largest alignment we need is 8 bytes (ptr/int64), since we don't use long
433 * double or __aligned attribute.
434 * This conservatively estimates that size 32 needs alignment of 8 (even if it might only
435 * need an alignment of 4).
436 */
437 switch (size % 8) {
438 case 0:
439 return 8;
440 case 2:
441 case 6:
442 return 2;
443 case 4:
444 return 4;
445 default:
446 return 1;
447 }
448 }
449
alignto(size_t p,size_t size)450 static inline size_t alignto(size_t p, size_t size)
451 {
452 /* size is power of 2 */
453 return (p + size - 1) & (~(size - 1));
454 }
455
mpool_create()456 struct MP *mpool_create()
457 {
458 struct MP mp, *mpool_p;
459 size_t sz;
460 memset(&mp, 0, sizeof(mp));
461 mp.psize = cli_getpagesize();
462 sz = align_to_pagesize(&mp, MIN_FRAGSIZE);
463 mp.u.mpm.usize = sizeof(struct MPMAP);
464 mp.u.mpm.size = sz - sizeof(mp);
465 if (FRAGSBITS > 255) {
466 cli_errmsg("At most 255 frags possible!\n");
467 return NULL;
468 }
469 if (fragsz[0] < sizeof(void *)) {
470 cli_errmsg("fragsz[0] too small!\n");
471 return NULL;
472 }
473 #ifndef _WIN32
474 if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
475 #else
476 if (!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
477 #endif
478 return NULL;
479 #ifdef CL_DEBUG
480 memset(mpool_p, ALLOCPOISON, sz);
481 #endif
482 memcpy(mpool_p, &mp, sizeof(mp));
483 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);
484 return mpool_p;
485 }
486
mpool_destroy(struct MP * mp)487 void mpool_destroy(struct MP *mp)
488 {
489 struct MPMAP *mpm_next = mp->u.mpm.next, *mpm;
490 size_t mpmsize;
491
492 spam("Destroying map @%p\n", mp);
493 while ((mpm = mpm_next)) {
494 mpmsize = mpm->size;
495 mpm_next = mpm->next;
496 #ifdef CL_DEBUG
497 memset(mpm, FREEPOISON, mpmsize);
498 #endif
499 #ifndef _WIN32
500 munmap((void *)mpm, mpmsize);
501 #else
502 VirtualFree(mpm, 0, MEM_RELEASE);
503 #endif
504 }
505 mpmsize = mp->u.mpm.size;
506 #ifdef CL_DEBUG
507 memset(mp, FREEPOISON, mpmsize + sizeof(*mp));
508 #endif
509 #ifndef _WIN32
510 munmap((void *)mp, mpmsize + sizeof(*mp));
511 #else
512 VirtualFree(mp, 0, MEM_RELEASE);
513 #endif
514 }
515
mpool_flush(struct MP * mp)516 void mpool_flush(struct MP *mp)
517 {
518 size_t used = 0, mused;
519 struct MPMAP *mpm_next = mp->u.mpm.next, *mpm;
520
521 #ifdef EXIT_ON_FLUSH
522 exit(0);
523 #endif
524
525 while ((mpm = mpm_next)) {
526 mpm_next = mpm->next;
527 mused = align_to_pagesize(mp, mpm->usize);
528 if (mused < mpm->size) {
529 #ifdef CL_DEBUG
530 memset((char *)mpm + mused, FREEPOISON, mpm->size - mused);
531 #endif
532 #ifndef _WIN32
533 munmap((char *)mpm + mused, mpm->size - mused);
534 #else
535 VirtualFree((char *)mpm + mused, mpm->size - mused, MEM_DECOMMIT);
536 #endif
537 mpm->size = mused;
538 }
539 used += mpm->size;
540 }
541
542 mused = align_to_pagesize(mp, mp->u.mpm.usize + sizeof(*mp));
543 if (mused < mp->u.mpm.size + sizeof(*mp)) {
544 #ifdef CL_DEBUG
545 memset((char *)mp + mused, FREEPOISON, mp->u.mpm.size + sizeof(*mp) - mused);
546 #endif
547 #ifndef _WIN32
548 munmap((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused);
549 #else
550 VirtualFree((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused, MEM_DECOMMIT);
551 #endif
552 mp->u.mpm.size = mused - sizeof(*mp);
553 }
554 used += mp->u.mpm.size;
555 cli_dbgmsg("pool memory used: %.3f MB\n", used / (1024 * 1024.0));
556 spam("Map flushed @%p, in use: %lu\n", mp, (unsigned long)used);
557 }
558
mpool_getstats(const struct cl_engine * eng,size_t * used,size_t * total)559 int mpool_getstats(const struct cl_engine *eng, size_t *used, size_t *total)
560 {
561 size_t sum_used = 0, sum_total = 0;
562 const struct MPMAP *mpm;
563 const mpool_t *mp;
564
565 /* checking refcount is not necessary, but safer */
566 if (!eng || !eng->refcount)
567 return -1;
568 mp = eng->mempool;
569 if (!mp)
570 return -1;
571 for (mpm = &mp->u.mpm; mpm; mpm = mpm->next) {
572 sum_used += mpm->usize;
573 sum_total += mpm->size;
574 }
575 *used = sum_used;
576 *total = sum_total;
577 return 0;
578 }
579
align_increase(size_t size,size_t a)580 static inline size_t align_increase(size_t size, size_t a)
581 {
582 /* we must pad with at most a-1 bytes to align start of struct */
583 return size + a - 1;
584 }
585
allocate_aligned(struct MPMAP * mpm,size_t size,unsigned align,const char * dbg)586 static void *allocate_aligned(struct MPMAP *mpm, size_t size, unsigned align, const char *dbg)
587 {
588 /* We could always align the size to maxalign (8), however that wastes
589 * space.
590 * So just align the start of each allocation as needed, and then see in
591 * which sbits bin we fit into.
592 * Since we are no longer allocating in multiple of 8, we must always
593 * align the start of each allocation!
594 *| end of previous allocation | padding | FRAG_OVERHEAD | ptr_aligned |*/
595 unsigned p = mpm->usize + FRAG_OVERHEAD;
596 unsigned p_aligned = alignto(p, align);
597 struct FRAG *f = (struct FRAG *)((char *)mpm + p_aligned - FRAG_OVERHEAD);
598 unsigned realneed = p_aligned + size - mpm->usize;
599 unsigned int sbits = to_bits(realneed);
600 size_t needed = from_bits(sbits);
601 #ifdef CL_DEBUG
602 assert(p_aligned + size <= mpm->size);
603 #endif
604 f->u.a.sbits = sbits;
605 f->u.a.padding = p_aligned - p;
606
607 mpm->usize += needed;
608 #ifdef CL_DEBUG
609 assert(mpm->usize <= mpm->size);
610 #endif
611 spam("malloc @%p size %lu (%s) origsize %lu overhead %lu\n", f, (unsigned long)realneed, dbg, (unsigned long)size, (unsigned long)(needed - size));
612 #ifdef CL_DEBUG
613 f->magic = MPOOLMAGIC;
614 memset(&f->u.a.fake, ALLOCPOISON, size);
615 #endif
616 return &f->u.a.fake;
617 }
618
mpool_malloc(struct MP * mp,size_t size)619 void *mpool_malloc(struct MP *mp, size_t size)
620 {
621 size_t align = alignof(size);
622 size_t i, needed = align_increase(size + FRAG_OVERHEAD, align);
623 const unsigned int sbits = to_bits(needed);
624 struct FRAG *f = NULL;
625 struct MPMAP *mpm = &mp->u.mpm;
626
627 /* check_all(mp); */
628 if (!size || sbits == FRAGSBITS) {
629 cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to https://github.com/Cisco-Talos/clamav/issues\n", (unsigned long)size);
630 return NULL;
631 }
632
633 /* Case 1: We have a free'd frag */
634 if ((f = mp->avail[sbits])) {
635 struct FRAG *fold = f;
636 mp->avail[sbits] = f->u.next.ptr;
637 /* we always have enough space for this, align_increase ensured that */
638 #ifdef _WIN64
639 f = (struct FRAG *)(alignto((unsigned long long)f + FRAG_OVERHEAD, align) - FRAG_OVERHEAD);
640 #else
641 f = (struct FRAG *)(alignto((unsigned long)f + FRAG_OVERHEAD, align) - FRAG_OVERHEAD);
642 #endif
643 f->u.a.sbits = sbits;
644 f->u.a.padding = (char *)f - (char *)fold;
645 #ifdef CL_DEBUG
646 f->magic = MPOOLMAGIC;
647 memset(&f->u.a.fake, ALLOCPOISON, size);
648 #endif
649 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));
650 return &f->u.a.fake;
651 }
652
653 if (!(needed = from_bits(sbits))) {
654 cli_errmsg("mpool_malloc(): Attempt to allocate %lu bytes. Please report to https://github.com/Cisco-Talos/clamav/issues\n", (unsigned long)size);
655 return NULL;
656 }
657
658 /* Case 2: We have nuff room available for this frag already */
659 while (mpm) {
660 if (mpm->size - mpm->usize >= needed)
661 return allocate_aligned(mpm, size, align, "hole");
662 mpm = mpm->next;
663 }
664
665 /* Case 3: We allocate more */
666 if (needed + sizeof(*mpm) > MIN_FRAGSIZE)
667 i = align_to_pagesize(mp, needed + sizeof(*mpm));
668 else
669 i = align_to_pagesize(mp, MIN_FRAGSIZE);
670
671 #ifndef _WIN32
672 if ((mpm = (struct MPMAP *)mmap(NULL, i, PROT_READ | PROT_WRITE, MAP_PRIVATE | ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) {
673 #else
674 if (!(mpm = (struct MPMAP *)VirtualAlloc(NULL, i, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))) {
675 #endif
676 cli_errmsg("mpool_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long)i);
677 spam("failed to alloc %lu bytes (%lu requested)\n", (unsigned long)i, (unsigned long)size);
678 return NULL;
679 }
680 #ifdef CL_DEBUG
681 memset(mpm, ALLOCPOISON, i);
682 #endif
683 mpm->size = i;
684 mpm->usize = sizeof(*mpm);
685 mpm->next = mp->u.mpm.next;
686 mp->u.mpm.next = mpm;
687 return allocate_aligned(mpm, size, align, "new map");
688 }
689
690 static void *allocbase_fromfrag(struct FRAG *f)
691 {
692 #ifdef CL_DEBUG
693 assert(f->u.a.padding < 8);
694 #endif
695 return (char *)f - f->u.a.padding;
696 }
697
698 void mpool_free(struct MP *mp, void *ptr)
699 {
700 struct FRAG *f = (struct FRAG *)((char *)ptr - FRAG_OVERHEAD);
701 unsigned int sbits;
702 if (!ptr) return;
703
704 #ifdef CL_DEBUG
705 assert(f->magic == MPOOLMAGIC && "Attempt to mpool_free a pointer we did not allocate!");
706 #endif
707
708 spam("free @%p\n", f);
709 sbits = f->u.a.sbits;
710 f = allocbase_fromfrag(f);
711 #ifdef CL_DEBUG
712 memset(f, FREEPOISON, from_bits(sbits));
713 #endif
714
715 f->u.next.ptr = mp->avail[sbits];
716 mp->avail[sbits] = f;
717 }
718
719 void *mpool_calloc(struct MP *mp, size_t nmemb, size_t size)
720 {
721 size_t needed = nmemb * size;
722 void *ptr;
723
724 if (!needed) return NULL;
725 if ((ptr = mpool_malloc(mp, needed)))
726 memset(ptr, 0, needed);
727 return ptr;
728 }
729
730 void *mpool_realloc(struct MP *mp, void *ptr, size_t size)
731 {
732 struct FRAG *f = (struct FRAG *)((char *)ptr - FRAG_OVERHEAD);
733 size_t csize;
734 void *new_ptr;
735 if (!ptr) return mpool_malloc(mp, size);
736
737 if (!size || !(csize = from_bits(f->u.a.sbits))) {
738 cli_errmsg("mpool_realloc(): Attempt to allocate %lu bytes. Please report to https://github.com/Cisco-Talos/clamav/issues\n", (unsigned long)size);
739 return NULL;
740 }
741 csize -= FRAG_OVERHEAD + f->u.a.padding;
742 if (csize >= size && (!f->u.a.sbits || from_bits(f->u.a.sbits - 1) - FRAG_OVERHEAD - f->u.a.padding < size)) {
743 spam("free @%p\n", f);
744 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));
745 return ptr;
746 }
747 if (!(new_ptr = mpool_malloc(mp, size)))
748 return NULL;
749 memcpy(new_ptr, ptr, csize <= size ? csize : size);
750 mpool_free(mp, ptr);
751 return new_ptr;
752 }
753
754 void *mpool_realloc2(struct MP *mp, void *ptr, size_t size)
755 {
756 void *new_ptr = mpool_realloc(mp, ptr, size);
757 if (new_ptr)
758 return new_ptr;
759 mpool_free(mp, ptr);
760 return NULL;
761 }
762
763 char *cli_mpool_hex2str(mpool_t *mp, const char *hex)
764 {
765 char *str;
766 size_t len = strlen((const char *)hex);
767
768 if (len & 1) {
769 cli_errmsg("cli_mpool_hex2str(): Malformed hexstring: %s (length: %lu)\n", hex, (unsigned long)len);
770 return NULL;
771 }
772
773 str = mpool_malloc(mp, (len / 2) + 1);
774 if (str == NULL) { /* oops, we have a memory pool allocation failure */
775 cli_errmsg("cli_mpool_hex2str(): Can't allocate memory (%lu bytes).\n", (unsigned long)(len / 2 + 1));
776 return NULL;
777 }
778 if (cli_hex2str_to(hex, str, len) == -1) {
779 mpool_free(mp, str);
780 return NULL;
781 }
782 str[len / 2] = '\0';
783 return str;
784 }
785
786 char *cli_mpool_strdup(mpool_t *mp, const char *s)
787 {
788 char *alloc;
789 size_t strsz;
790
791 if (s == NULL) {
792 cli_errmsg("cli_mpool_strdup(): s == NULL. Please report to https://github.com/Cisco-Talos/clamav/issues\n");
793 return NULL;
794 }
795
796 strsz = strlen(s) + 1;
797 alloc = mpool_malloc(mp, strsz);
798 if (!alloc)
799 cli_errmsg("cli_mpool_strdup(): Can't allocate memory (%lu bytes).\n", (unsigned long)strsz);
800 else
801 memcpy(alloc, s, strsz);
802 return alloc;
803 }
804
805 char *cli_mpool_strndup(mpool_t *mp, const char *s, size_t n)
806 {
807 char *alloc;
808 size_t strsz;
809
810 if (s == NULL) {
811 cli_errmsg("cli_mpool_strndup(): s == NULL. Please report to https://github.com/Cisco-Talos/clamav/issues\n");
812 return NULL;
813 }
814
815 strsz = CLI_STRNLEN(s, n) + 1;
816 alloc = mpool_malloc(mp, strsz);
817 if (!alloc)
818 cli_errmsg("cli_mpool_strndup(): Can't allocate memory (%lu bytes).\n", (unsigned long)strsz);
819 else
820 memcpy(alloc, s, strsz - 1);
821 alloc[strsz - 1] = '\0';
822 return alloc;
823 }
824
825 /* #define EXPAND_PUA */
826 char *cli_mpool_virname(mpool_t *mp, const char *virname, unsigned int official)
827 {
828 char *newname, *pt;
829 #ifdef EXPAND_PUA
830 char buf[1024];
831 #endif
832
833 if (!virname)
834 return NULL;
835
836 if ((pt = strchr(virname, ' ')))
837 if ((pt = strstr(pt, " (Clam)")))
838 *pt = '\0';
839
840 if (!virname[0]) {
841 cli_errmsg("cli_mpool_virname: Empty virus name\n");
842 return NULL;
843 }
844
845 #ifdef EXPAND_PUA
846 if (!strncmp(virname, "PUA.", 4)) {
847 snprintf(buf, sizeof(buf), "Possibly-Unwanted-Application(www.clamav.net/support/pua).%s", virname + 4);
848 buf[sizeof(buf) - 1] = '\0';
849 virname = buf;
850 }
851 #endif
852 if (official)
853 return cli_mpool_strdup(mp, virname);
854
855 newname = (char *)mpool_malloc(mp, strlen(virname) + 11 + 1);
856 if (!newname) {
857 cli_errmsg("cli_mpool_virname: Can't allocate memory for newname\n");
858 return NULL;
859 }
860 sprintf(newname, "%s.UNOFFICIAL", virname);
861 return newname;
862 }
863
864 uint16_t *cli_mpool_hex2ui(mpool_t *mp, const char *hex)
865 {
866 uint16_t *str;
867 size_t len;
868
869 len = strlen(hex);
870
871 if (len % 2 != 0) {
872 cli_errmsg("cli_mpool_hex2ui(): Malformed hexstring: %s (length: %lu)\n", hex, (unsigned long)len);
873 return NULL;
874 }
875
876 str = mpool_calloc(mp, (len / 2) + 1, sizeof(uint16_t));
877 if (!str)
878 return NULL;
879
880 if (cli_realhex2ui(hex, str, len))
881 return str;
882
883 mpool_free(mp, str);
884 return NULL;
885 }
886
887 #ifdef DEBUGMPOOL
888 void mpool_stats(struct MP *mp)
889 {
890 size_t i = 0, ta = 0, tu = 0;
891 struct MPMAP *mpm = &mp->u.mpm;
892
893 cli_warnmsg("MEMORY POOL STATISTICS\n map \tsize\tused\t%\n");
894 while (mpm) {
895 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);
896 ta += mpm->size;
897 tu += mpm->usize;
898 i++;
899 mpm = mpm->next;
900 }
901 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);
902 }
903
904 void check_all(struct MP *mp)
905 {
906 struct MPMAP *mpm = &mp->u.mpm;
907 while (mpm) {
908 volatile unsigned char *c = (unsigned char *)mpm;
909 size_t len = mpm->size;
910 spam("checking object %p - size %lu\n", mpm, (unsigned long)len);
911 while (len--) {
912 c[len];
913 }
914 mpm = mpm->next;
915 }
916 }
917 #endif /* DEBUGMPOOL */
918
919 #else
920 /* dummy definitions to make Solaris linker happy.
921 * these symbols are declared in libclamav.map */
922 void mpool_free() {}
923 void mpool_create() {}
924 void mpool_destroy() {}
925 void mpool_getstats() {}
926 void mpool_calloc() {}
927
928 #endif /* USE_MPOOL */
929