• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

53.94
/src/util-pool.c
1
/* Copyright (C) 2007-2010 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \defgroup utilpool Pool
20
 *
21
 * ::Pool are an effective way to maintain a set of ready to use
22
 * structures.
23
 *
24
 * To create a ::Pool, you need to use PoolInit(). You can
25
 * get an item from the ::Pool by using PoolGet(). When you're
26
 * done with it call PoolReturn().
27
 * To destroy the ::Pool, call PoolFree(), it will free all used
28
 * memory.
29
 *
30
 * @{
31
 */
32

33
/**
34
 * \file
35
 *
36
 * \author Victor Julien <victor@inliniac.net>
37
 *
38
 * Pool utility functions
39
 */
40

41
#include "suricata-common.h"
42
#include "util-pool.h"
43
#include "util-pool-thread.h"
44
#include "util-unittest.h"
45
#include "util-debug.h"
46

47
static int PoolMemset(void *pitem, void *initdata)
UNCOV
48
{
×
UNCOV
49
    Pool *p = (Pool *) initdata;
×
50

UNCOV
51
    memset(pitem, 0, p->elt_size);
×
UNCOV
52
    return 1;
×
UNCOV
53
}
×
54

55
/**
56
 * \brief Check if data is preallocated
57
 * \retval false if not inside the prealloc'd block, true if inside */
58
static bool PoolDataPreAllocated(Pool *p, void *data)
59
{
43,854✔
60
    ptrdiff_t delta = data - p->data_buffer;
43,854✔
61
    if ((delta < 0) || (delta > p->data_buffer_size)) {
43,854✔
62
        return false;
43,854✔
63
    }
43,854✔
UNCOV
64
    return true;
×
65
}
43,854✔
66

67
/** \brief Init a Pool
68
 *
69
 * PoolInit() creates a ::Pool. The Alloc function must only do
70
 * allocation stuff. The Cleanup function must not try to free
71
 * the PoolBucket::data. This is done by the ::Pool management
72
 * system.
73
 *
74
 * \param size
75
 * \param prealloc_size
76
 * \param elt_size Memory size of an element
77
 * \param Alloc An allocation function or NULL to use a standard SCMalloc
78
 * \param Init An init function or NULL to use a standard memset to 0
79
 * \param InitData Init data
80
 * \param Cleanup a free function or NULL if no special treatment is needed
81
 * \param Free free func
82
 * \retval the allocated Pool
83
 */
84
Pool *PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size,
85
        void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData,
86
        void (*Cleanup)(void *), void (*Free)(void *))
87
{
4✔
88
    sc_errno = SC_OK;
4✔
89

90
    Pool *p = NULL;
4✔
91

92
    if (size != 0 && prealloc_size > size) {
4✔
93
        sc_errno = SC_EINVAL;
×
94
        goto error;
×
95
    }
×
96
    if (size != 0 && elt_size == 0) {
4✔
97
        sc_errno = SC_EINVAL;
×
98
        goto error;
×
99
    }
×
100
    if (elt_size && Free) {
4✔
101
        sc_errno = SC_EINVAL;
×
102
        goto error;
×
103
    }
×
104
    if (elt_size == 0 && Alloc == NULL) {
4✔
105
        sc_errno = SC_EINVAL;
×
106
        goto error;
×
107
    }
×
108

109
    /* setup the filter */
110
    p = SCCalloc(1, sizeof(Pool));
4✔
111
    if (unlikely(p == NULL)) {
4✔
112
        sc_errno = SC_ENOMEM;
×
113
        goto error;
×
114
    }
×
115

116
    p->max_buckets = size;
4✔
117
    p->preallocated = prealloc_size;
4✔
118
    p->elt_size = elt_size;
4✔
119
    p->data_buffer_size = prealloc_size * elt_size;
4✔
120
    p->Alloc = Alloc;
4✔
121
    p->Init = Init;
4✔
122
    p->InitData = InitData;
4✔
123
    p->Cleanup = Cleanup;
4✔
124
    p->Free = Free;
4✔
125
    if (p->Init == NULL) {
4✔
UNCOV
126
        p->Init = PoolMemset;
×
UNCOV
127
        p->InitData = p;
×
UNCOV
128
    }
×
129

130
    /* alloc the buckets and place them in the empty list */
131
    uint32_t u32 = 0;
4✔
132
    if (size > 0) {
4✔
133
        PoolBucket *pb = SCCalloc(size, sizeof(PoolBucket));
2✔
134
        if (unlikely(pb == NULL)) {
2✔
135
            sc_errno = SC_ENOMEM;
×
136
            goto error;
×
137
        }
×
138
        memset(pb, 0, size * sizeof(PoolBucket));
2✔
139
        p->pb_buffer = pb;
2✔
140
        for (u32 = 0; u32 < size; u32++) {
131,072✔
141
            /* populate pool */
142
            pb->next = p->empty_stack;
131,070✔
143
            pb->flags |= POOL_BUCKET_PREALLOCATED;
131,070✔
144
            p->empty_stack = pb;
131,070✔
145
            p->empty_stack_size++;
131,070✔
146
            pb++;
131,070✔
147
        }
131,070✔
148

149
        p->data_buffer = SCCalloc(prealloc_size, elt_size);
2✔
150
        /* FIXME better goto */
151
        if (p->data_buffer == NULL) {
2✔
152
            sc_errno = SC_ENOMEM;
×
153
            goto error;
×
154
        }
×
155
    }
2✔
156
    /* prealloc the buckets and requeue them to the alloc list */
157
    for (u32 = 0; u32 < prealloc_size; u32++) {
69,634✔
158
        if (size == 0) { /* unlimited */
69,630✔
159
            PoolBucket *pb = SCCalloc(1, sizeof(PoolBucket));
4,096✔
160
            if (unlikely(pb == NULL)) {
4,096✔
161
                sc_errno = SC_ENOMEM;
×
162
                goto error;
×
163
            }
×
164

165
            if (p->Alloc) {
4,096✔
166
                pb->data = p->Alloc();
4,096✔
167
            } else {
4,096✔
168
                pb->data = SCMalloc(p->elt_size);
×
169
            }
×
170
            if (pb->data == NULL) {
4,096✔
171
                SCFree(pb);
×
172
                sc_errno = SC_ENOMEM;
×
173
                goto error;
×
174
            }
×
175
            if (p->Init(pb->data, p->InitData) != 1) {
4,096✔
176
                if (p->Free)
×
177
                    p->Free(pb->data);
×
178
                else
×
179
                    SCFree(pb->data);
×
180
                SCFree(pb);
×
181
                sc_errno = SC_EINVAL;
×
182
                goto error;
×
183
            }
×
184
            p->allocated++;
4,096✔
185

186
            pb->next = p->alloc_stack;
4,096✔
187
            p->alloc_stack = pb;
4,096✔
188
            p->alloc_stack_size++;
4,096✔
189
        } else {
65,534✔
190
            PoolBucket *pb = p->empty_stack;
65,534✔
191
            if (pb == NULL) {
65,534✔
192
                sc_errno = SC_ENOMEM;
×
193
                goto error;
×
194
            }
×
195

196
            pb->data = (char *)p->data_buffer + u32 * elt_size;
65,534✔
197
            if (p->Init(pb->data, p->InitData) != 1) {
65,534✔
198
                pb->data = NULL;
×
199
                sc_errno = SC_EINVAL;
×
200
                goto error;
×
201
            }
×
202

203
            p->empty_stack = pb->next;
65,534✔
204
            p->empty_stack_size--;
65,534✔
205

206
            p->allocated++;
65,534✔
207

208
            pb->next = p->alloc_stack;
65,534✔
209
            p->alloc_stack = pb;
65,534✔
210
            p->alloc_stack_size++;
65,534✔
211
        }
65,534✔
212
    }
69,630✔
213

214
    return p;
4✔
215

216
error:
×
217
    if (p != NULL) {
×
218
        PoolFree(p);
×
219
    }
×
220
    return NULL;
×
221
}
4✔
222

223
void PoolFree(Pool *p)
UNCOV
224
{
×
UNCOV
225
    if (p == NULL)
×
226
        return;
×
227

UNCOV
228
    while (p->alloc_stack != NULL) {
×
UNCOV
229
        PoolBucket *pb = p->alloc_stack;
×
UNCOV
230
        p->alloc_stack = pb->next;
×
UNCOV
231
        if (p->Cleanup)
×
UNCOV
232
            p->Cleanup(pb->data);
×
UNCOV
233
        if (!PoolDataPreAllocated(p, pb->data)) {
×
UNCOV
234
            if (p->Free)
×
235
                p->Free(pb->data);
×
UNCOV
236
            else
×
UNCOV
237
                SCFree(pb->data);
×
UNCOV
238
        }
×
UNCOV
239
        pb->data = NULL;
×
UNCOV
240
        if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
×
UNCOV
241
            SCFree(pb);
×
UNCOV
242
        }
×
UNCOV
243
    }
×
244

UNCOV
245
    while (p->empty_stack != NULL) {
×
UNCOV
246
        PoolBucket *pb = p->empty_stack;
×
UNCOV
247
        p->empty_stack = pb->next;
×
UNCOV
248
        if (pb->data!= NULL) {
×
249
            if (p->Cleanup)
×
250
                p->Cleanup(pb->data);
×
251
            if (!PoolDataPreAllocated(p, pb->data)) {
×
252
                if (p->Free)
×
253
                    p->Free(pb->data);
×
254
                else
×
255
                    SCFree(pb->data);
×
256
            }
×
257
            pb->data = NULL;
×
258
        }
×
UNCOV
259
        if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
×
260
            SCFree(pb);
×
261
        }
×
UNCOV
262
    }
×
263

UNCOV
264
    if (p->pb_buffer)
×
UNCOV
265
        SCFree(p->pb_buffer);
×
UNCOV
266
    if (p->data_buffer)
×
UNCOV
267
        SCFree(p->data_buffer);
×
UNCOV
268
    SCFree(p);
×
UNCOV
269
}
×
270

271
void *PoolGet(Pool *p)
272
{
591,183✔
273
    SCEnter();
591,183✔
274

275
    PoolBucket *pb = p->alloc_stack;
591,183✔
276
    if (pb != NULL) {
591,183✔
277
        /* pull from the alloc list */
278
        p->alloc_stack = pb->next;
496,369✔
279
        p->alloc_stack_size--;
496,369✔
280

281
        /* put in the empty list */
282
        pb->next = p->empty_stack;
496,369✔
283
        p->empty_stack = pb;
496,369✔
284
        p->empty_stack_size++;
496,369✔
285
    } else {
496,369✔
286
        if (p->max_buckets == 0 || p->allocated < p->max_buckets) {
94,814✔
287
            void *pitem;
76,687✔
288
            SCLogDebug("max_buckets %"PRIu32"", p->max_buckets);
76,687✔
289

290
            if (p->Alloc != NULL) {
76,687✔
291
                pitem = p->Alloc();
43,919✔
292
            } else {
43,919✔
293
                pitem = SCMalloc(p->elt_size);
32,768✔
294
            }
32,768✔
295

296
            if (pitem != NULL) {
76,687✔
297
                if (p->Init(pitem, p->InitData) != 1) {
76,687✔
298
                    if (p->Free != NULL)
×
299
                        p->Free(pitem);
×
300
                    else
×
301
                        SCFree(pitem);
×
302
                    SCReturnPtr(NULL, "void");
×
303
                }
×
304

305
                p->allocated++;
76,687✔
306
                p->outstanding++;
76,687✔
307
#ifdef DEBUG
308
                if (p->outstanding > p->max_outstanding)
309
                    p->max_outstanding = p->outstanding;
310
#endif
311
            }
76,687✔
312

313
            SCReturnPtr(pitem, "void");
76,687✔
314
        } else {
76,687✔
315
            SCReturnPtr(NULL, "void");
18,127✔
316
        }
18,127✔
317
    }
94,814✔
318

319
    void *ptr = pb->data;
496,369✔
320
    pb->data = NULL;
496,369✔
321
    p->outstanding++;
496,369✔
322
#ifdef DEBUG
323
    if (p->outstanding > p->max_outstanding)
324
        p->max_outstanding = p->outstanding;
325
#endif
326
    SCReturnPtr(ptr,"void");
496,369✔
327
}
591,183✔
328

329
void PoolReturn(Pool *p, void *data)
330
{
509,159✔
331
    SCEnter();
509,159✔
332

333
    PoolBucket *pb = p->empty_stack;
509,159✔
334

335
    SCLogDebug("pb %p", pb);
509,159✔
336

337
    if (pb == NULL) {
509,159✔
338
        p->allocated--;
43,854✔
339
        p->outstanding--;
43,854✔
340
        if (p->Cleanup != NULL) {
43,854✔
341
            p->Cleanup(data);
43,854✔
342
        }
43,854✔
343
        if (!PoolDataPreAllocated(p, data)) {
43,854✔
344
            if (p->Free)
43,854✔
345
                p->Free(data);
×
346
            else
43,854✔
347
                SCFree(data);
43,854✔
348
        }
43,854✔
349

350
        SCLogDebug("tried to return data %p to the pool %p, but no more "
43,854✔
351
                   "buckets available. Just freeing the data.", data, p);
43,854✔
352
        SCReturn;
43,854✔
353
    }
43,854✔
354

355
    /* pull from the alloc list */
356
    p->empty_stack = pb->next;
465,305✔
357
    p->empty_stack_size--;
465,305✔
358

359
    /* put in the alloc list */
360
    pb->next = p->alloc_stack;
465,305✔
361
    p->alloc_stack = pb;
465,305✔
362
    p->alloc_stack_size++;
465,305✔
363

364
    pb->data = data;
465,305✔
365
    p->outstanding--;
465,305✔
366
    SCReturn;
465,305✔
367
}
509,159✔
368

369
/*
370
 * ONLY TESTS BELOW THIS COMMENT
371
 */
372

373
#ifdef UNITTESTS
374
static void *PoolTestAlloc(void)
375
{
376
    void *ptr = SCMalloc(10);
377
    if (unlikely(ptr == NULL))
378
        return NULL;
379
    return ptr;
380
}
381
static int PoolTestInitArg(void *data, void *allocdata)
382
{
383
    size_t len = strlen((char *)allocdata) + 1;
384
    char *str = data;
385
    if (str != NULL)
386
        strlcpy(str,(char *)allocdata,len);
387
    return 1;
388
}
389

390
static void PoolTestFree(void *ptr)
391
{
392
}
393

394
static int PoolTestInit01 (void)
395
{
396
    Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
397
    FAIL_IF_NOT(p != NULL);
398

399
    PoolFree(p);
400
    PASS;
401
}
402

403
static int PoolTestInit02 (void)
404
{
405
    Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
406
    FAIL_IF_NOT(p != NULL);
407

408
    FAIL_IF_NOT(p->alloc_stack != NULL);
409

410
    FAIL_IF_NOT(p->empty_stack != NULL);
411

412
    FAIL_IF_NOT(p->Alloc == PoolTestAlloc);
413

414
    FAIL_IF_NOT(p->Cleanup == PoolTestFree);
415

416
    PoolFree(p);
417
    PASS;
418
}
419

420
static int PoolTestInit03 (void)
421
{
422
    Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
423
    FAIL_IF_NOT(p != NULL);
424

425
    void *data = PoolGet(p);
426
    FAIL_IF_NOT(data != NULL);
427

428
    FAIL_IF_NOT(p->alloc_stack_size == 4);
429

430
    FAIL_IF_NOT(p->empty_stack_size == 6);
431

432
    PoolFree(p);
433
    PASS;
434
}
435

436
static int PoolTestInit04 (void)
437
{
438
    Pool *p = PoolInit(10,5,strlen("test") + 1,NULL, PoolTestInitArg,(void *)"test",PoolTestFree, NULL);
439
    FAIL_IF_NOT(p != NULL);
440

441
    char *str = PoolGet(p);
442
    FAIL_IF_NOT(str != NULL);
443

444
    FAIL_IF_NOT(strcmp(str, "test") == 0);
445

446
    FAIL_IF_NOT(p->alloc_stack_size == 4);
447

448
    FAIL_IF_NOT(p->empty_stack_size == 6);
449

450
    PoolFree(p);
451
    PASS;
452
}
453

454
static int PoolTestInit05 (void)
455
{
456
    Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL, NULL,PoolTestFree, NULL);
457
    FAIL_IF_NOT(p != NULL);
458

459
    void *data = PoolGet(p);
460
    FAIL_IF_NOT(data != NULL);
461

462
    FAIL_IF_NOT(p->alloc_stack_size == 4);
463

464
    FAIL_IF_NOT(p->empty_stack_size == 6);
465

466
    PoolReturn(p, data);
467
    data = NULL;
468

469
    FAIL_IF_NOT(p->alloc_stack_size == 5);
470

471
    FAIL_IF_NOT(p->empty_stack_size == 5);
472

473
    PoolFree(p);
474
    PASS;
475
}
476

477
static int PoolTestInit06 (void)
478
{
479
    Pool *p = PoolInit(1,0,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
480
    FAIL_IF_NOT(p != NULL);
481

482
    FAIL_IF_NOT(p->allocated == 0);
483

484
    void *data = PoolGet(p);
485
    FAIL_IF_NOT(data != NULL);
486

487
    FAIL_IF_NOT(p->allocated == 1);
488

489
    void *data2 = PoolGet(p);
490
    FAIL_IF_NOT(data2 == NULL);
491

492
    PoolReturn(p,data);
493
    data = NULL;
494

495
    FAIL_IF_NOT(p->allocated == 1);
496

497
    FAIL_IF_NOT(p->alloc_stack_size == 1);
498

499
    PoolFree(p);
500
    PASS;
501
}
502

503
/** \test pool with unlimited size */
504
static int PoolTestInit07 (void)
505
{
506
    Pool *p = PoolInit(0,1,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
507
    FAIL_IF_NOT(p != NULL);
508

509
    FAIL_IF_NOT(p->max_buckets == 0);
510

511
    FAIL_IF_NOT(p->allocated == 1);
512

513
    void *data = PoolGet(p);
514
    FAIL_IF_NOT(data != NULL);
515

516
    FAIL_IF_NOT(p->allocated == 1);
517

518
    void *data2 = PoolGet(p);
519
    FAIL_IF_NOT(data2 != NULL);
520

521
    FAIL_IF_NOT(p->allocated == 2);
522

523
    PoolReturn(p,data);
524
    data = NULL;
525

526
    FAIL_IF_NOT(p->allocated == 2);
527

528
    FAIL_IF_NOT(p->alloc_stack_size == 1);
529

530
    PoolReturn(p,data2);
531
    data2 = NULL;
532

533
    FAIL_IF_NOT(p->allocated == 1);
534

535
    PoolFree(p);
536
    PASS;
537
}
538
#endif /* UNITTESTS */
539

540
void PoolRegisterTests(void)
UNCOV
541
{
×
542
#ifdef UNITTESTS
543
    UtRegisterTest("PoolTestInit01", PoolTestInit01);
544
    UtRegisterTest("PoolTestInit02", PoolTestInit02);
545
    UtRegisterTest("PoolTestInit03", PoolTestInit03);
546
    UtRegisterTest("PoolTestInit04", PoolTestInit04);
547
    UtRegisterTest("PoolTestInit05", PoolTestInit05);
548
    UtRegisterTest("PoolTestInit06", PoolTestInit06);
549
    UtRegisterTest("PoolTestInit07", PoolTestInit07);
550

551
    PoolThreadRegisterTests();
552
#endif /* UNITTESTS */
UNCOV
553
}
×
554

555

556
/**
557
 * @}
558
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc