• 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

75.53
/src/util-hashlist.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
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * Chained hash table implementation
24
 *
25
 * The 'Free' pointer can be used to have the API free your
26
 * hashed data. If it's NULL it's the callers responsibility
27
 */
28

29
#include "suricata-common.h"
30
#include "util-hashlist.h"
31
#include "util-unittest.h"
32
#include "util-debug.h"
33
#include "util-memcmp.h"
34

35
HashListTable *HashListTableInit(uint32_t size,
36
        uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t),
37
        char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *))
38
{
825,085✔
39
    sc_errno = SC_OK;
825,085✔
40
    HashListTable *ht = NULL;
825,085✔
41

42
    if (size == 0) {
825,085✔
UNCOV
43
        sc_errno = SC_EINVAL;
×
UNCOV
44
        goto error;
×
UNCOV
45
    }
×
46

47
    if (Hash == NULL) {
825,085✔
UNCOV
48
        sc_errno = SC_EINVAL;
×
UNCOV
49
        goto error;
×
UNCOV
50
    }
×
51

52
    /* setup the filter */
53
    ht = SCCalloc(1, sizeof(HashListTable));
825,085✔
54
    if (unlikely(ht == NULL)) {
825,085✔
55
        sc_errno = SC_ENOMEM;
×
56
        goto error;
×
57
    }
×
58
    ht->array_size = size;
825,085✔
59
    ht->Hash = Hash;
825,085✔
60
    ht->Free = Free;
825,085✔
61

62
    if (Compare != NULL)
825,085✔
63
        ht->Compare = Compare;
825,085✔
UNCOV
64
    else
×
UNCOV
65
        ht->Compare = HashListTableDefaultCompare;
×
66

67
    /* setup the bitarray */
68
    ht->array = SCCalloc(ht->array_size, sizeof(HashListTableBucket *));
825,085✔
69
    if (ht->array == NULL) {
825,085✔
70
        sc_errno = SC_ENOMEM;
×
71
        goto error;
×
72
    }
×
73

74
    ht->listhead = NULL;
825,085✔
75
    ht->listtail = NULL;
825,085✔
76
    return ht;
825,085✔
77

UNCOV
78
error:
×
UNCOV
79
    if (ht != NULL) {
×
80
        if (ht->array != NULL)
×
81
            SCFree(ht->array);
×
82

83
        SCFree(ht);
×
84
    }
×
UNCOV
85
    return NULL;
×
86
}
825,085✔
87

88
void HashListTableFree(HashListTable *ht)
89
{
851,970✔
90
    uint32_t i = 0;
851,970✔
91

92
    if (ht == NULL)
851,970✔
93
        return;
28,688✔
94

95
    /* free the buckets */
96
    for (i = 0; i < ht->array_size; i++) {
2,147,483,647✔
97
        HashListTableBucket *hashbucket = ht->array[i];
2,147,483,647✔
98
        while (hashbucket != NULL) {
2,147,483,647✔
99
            HashListTableBucket *next_hashbucket = hashbucket->bucknext;
49,244,052✔
100
            if (ht->Free != NULL)
49,244,052✔
101
                ht->Free(hashbucket->data);
34,475,473✔
102
            SCFree(hashbucket);
49,244,052✔
103
            hashbucket = next_hashbucket;
49,244,052✔
104
        }
49,244,052✔
105
    }
2,147,483,647✔
106

107
    /* free the array */
108
    if (ht->array != NULL)
823,282✔
109
        SCFree(ht->array);
823,282✔
110

111
    SCFree(ht);
823,282✔
112
}
823,282✔
113

114
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
115
{
49,602,689✔
116
    if (ht == NULL || data == NULL)
49,602,689✔
117
        return -1;
4✔
118

119
    uint32_t hash = ht->Hash(ht, data, datalen);
49,602,685✔
120

121
    SCLogDebug("ht %p hash %"PRIu32"", ht, hash);
49,602,685✔
122

123
    HashListTableBucket *hb = SCCalloc(1, sizeof(HashListTableBucket));
49,602,685✔
124
    if (unlikely(hb == NULL))
49,602,685✔
125
        goto error;
×
126
    hb->data = data;
49,602,685✔
127
    hb->size = datalen;
49,602,685✔
128
    hb->bucknext = NULL;
49,602,685✔
129
    hb->listnext = NULL;
49,602,685✔
130
    hb->listprev = NULL;
49,602,685✔
131

132
    if (ht->array[hash] == NULL) {
49,602,685✔
133
        ht->array[hash] = hb;
29,212,437✔
134
    } else {
29,212,437✔
135
        hb->bucknext = ht->array[hash];
20,390,248✔
136
        ht->array[hash] = hb;
20,390,248✔
137
    }
20,390,248✔
138

139
    if (ht->listtail == NULL) {
49,602,685✔
140
        ht->listhead = hb;
454,626✔
141
        ht->listtail = hb;
454,626✔
142
    } else {
49,148,059✔
143
        hb->listprev = ht->listtail;
49,148,059✔
144
        ht->listtail->listnext = hb;
49,148,059✔
145
        ht->listtail = hb;
49,148,059✔
146
    }
49,148,059✔
147

148
    return 0;
49,602,685✔
149

150
error:
×
151
    return -1;
×
152
}
49,602,685✔
153

154
int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen)
155
{
390,245✔
156
    uint32_t hash = ht->Hash(ht, data, datalen);
390,245✔
157

158
    SCLogDebug("ht %p hash %"PRIu32"", ht, hash);
390,245✔
159

160
    if (ht->array[hash] == NULL) {
390,245✔
161
        SCLogDebug("ht->array[hash] NULL");
45,971✔
162
        return -1;
45,971✔
163
    }
45,971✔
164

165
    /* fast track for just one data part */
166
    if (ht->array[hash]->bucknext == NULL) {
344,274✔
167
        HashListTableBucket *hb = ht->array[hash];
323,323✔
168

169
        if (ht->Compare(hb->data,hb->size,data,datalen) == 1) {
323,323✔
170
            /* remove from the list */
171
            if (hb->listprev == NULL) {
322,616✔
172
                ht->listhead = hb->listnext;
82,393✔
173
            } else {
240,223✔
174
                hb->listprev->listnext = hb->listnext;
240,223✔
175
            }
240,223✔
176
            if (hb->listnext == NULL) {
322,616✔
177
                ht->listtail = hb->listprev;
207,505✔
178
            } else {
207,505✔
179
                hb->listnext->listprev = hb->listprev;
115,111✔
180
            }
115,111✔
181

182
            if (ht->Free != NULL)
322,616✔
183
                ht->Free(hb->data);
322,616✔
184

185
            SCFree(ht->array[hash]);
322,616✔
186
            ht->array[hash] = NULL;
322,616✔
187
            return 0;
322,616✔
188
        }
322,616✔
189

190
        SCLogDebug("fast track default case");
707✔
191
        return -1;
707✔
192
    }
323,323✔
193

194
    /* more data in this bucket */
195
    HashListTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL;
20,951✔
196
    do {
30,779✔
197
        if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) {
30,779✔
198

199
            /* remove from the list */
200
            if (hashbucket->listprev == NULL) {
20,931✔
201
                ht->listhead = hashbucket->listnext;
4,245✔
202
            } else {
16,686✔
203
                hashbucket->listprev->listnext = hashbucket->listnext;
16,686✔
204
            }
16,686✔
205
            if (hashbucket->listnext == NULL) {
20,931✔
206
                ht->listtail = hashbucket->listprev;
3,795✔
207
            } else {
17,136✔
208
                hashbucket->listnext->listprev = hashbucket->listprev;
17,136✔
209
            }
17,136✔
210

211
            if (prev_hashbucket == NULL) {
20,931✔
212
                /* root bucket */
213
                ht->array[hash] = hashbucket->bucknext;
12,374✔
214
            } else {
12,374✔
215
                /* child bucket */
216
                prev_hashbucket->bucknext = hashbucket->bucknext;
8,557✔
217
            }
8,557✔
218

219
            /* remove this */
220
            if (ht->Free != NULL)
20,931✔
221
                ht->Free(hashbucket->data);
20,931✔
222
            SCFree(hashbucket);
20,931✔
223
            return 0;
20,931✔
224
        }
20,931✔
225

226
        prev_hashbucket = hashbucket;
9,848✔
227
        hashbucket = hashbucket->bucknext;
9,848✔
228
    } while (hashbucket != NULL);
9,848✔
229

230
    SCLogDebug("slow track default case");
20✔
231
    return -1;
20✔
232
}
20,951✔
233

234
char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2)
UNCOV
235
{
×
UNCOV
236
    if (len1 != len2)
×
237
        return 0;
×
238

UNCOV
239
    if (SCMemcmp(data1,data2,len1) != 0)
×
240
        return 0;
×
241

UNCOV
242
    return 1;
×
UNCOV
243
}
×
244

245
void *HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
246
{
54,233,918✔
247

248
    if (ht == NULL) {
54,233,918✔
249
        SCLogDebug("Hash List table is NULL");
115✔
250
        return NULL;
115✔
251
    }
115✔
252

253
    uint32_t hash = ht->Hash(ht, data, datalen);
54,233,803✔
254

255
    if (ht->array[hash] == NULL) {
54,233,803✔
256
        return NULL;
12,747,267✔
257
    }
12,747,267✔
258

259
    HashListTableBucket *hashbucket = ht->array[hash];
41,486,536✔
260
    do {
59,342,103✔
261
        if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1)
59,342,103✔
262
            return hashbucket->data;
32,970,728✔
263

264
        hashbucket = hashbucket->bucknext;
26,371,375✔
265
    } while (hashbucket != NULL);
26,371,375✔
266

267
    return NULL;
8,515,808✔
268
}
41,486,536✔
269

270
uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen)
UNCOV
271
{
×
UNCOV
272
     uint8_t *d = (uint8_t *)data;
×
UNCOV
273
     uint32_t i;
×
UNCOV
274
     uint32_t hash = 0;
×
275

UNCOV
276
     for (i = 0; i < datalen; i++) {
×
UNCOV
277
         if (i == 0)      hash += (((uint32_t)*d++));
×
UNCOV
278
         else if (i == 1) hash += (((uint32_t)*d++) * datalen);
×
UNCOV
279
         else             hash *= (((uint32_t)*d++) * i) + datalen + i;
×
UNCOV
280
     }
×
281

UNCOV
282
     hash *= datalen;
×
UNCOV
283
     hash %= ht->array_size;
×
UNCOV
284
     return hash;
×
UNCOV
285
}
×
286

287
HashListTableBucket *HashListTableGetListHead(HashListTable *ht)
288
{
755,971✔
289
    return ht->listhead;
755,971✔
290
}
755,971✔
291

292
/*
293
 * ONLY TESTS BELOW THIS COMMENT
294
 */
295

296
#ifdef UNITTESTS
297
static int HashListTableTestInit01 (void)
298
{
299
    HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL);
300
    if (ht == NULL)
301
        return 0;
302

303
    HashListTableFree(ht);
304
    return 1;
305
}
306

307
/* no hash function, so it should fail */
308
static int HashListTableTestInit02 (void)
309
{
310
    HashListTable *ht = HashListTableInit(1024, NULL, NULL, NULL);
311
    if (ht == NULL)
312
        return 1;
313

314
    HashListTableFree(ht);
315
    return 0;
316
}
317

318
static int HashListTableTestInit03 (void)
319
{
320
    int result = 0;
321
    HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL);
322
    if (ht == NULL)
323
        return 0;
324

325
    if (ht->Hash == HashListTableGenericHash)
326
        result = 1;
327

328
    HashListTableFree(ht);
329
    return result;
330
}
331

332
static int HashListTableTestInit04 (void)
333
{
334
    HashListTable *ht = HashListTableInit(0, HashListTableGenericHash, NULL, NULL);
335
    if (ht == NULL)
336
        return 1;
337

338
    HashListTableFree(ht);
339
    return 0;
340
}
341

342
static int HashListTableTestAdd01 (void)
343
{
344
    int result = 0;
345
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
346
    if (ht == NULL)
347
        goto end;
348

349
    int r = HashListTableAdd(ht, (char *)"test", 0);
350
    if (r != 0)
351
        goto end;
352

353
    /* all is good! */
354
    result = 1;
355
end:
356
    if (ht != NULL) HashListTableFree(ht);
357
    return result;
358
}
359

360
static int HashListTableTestAdd02 (void)
361
{
362
    int result = 0;
363
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
364
    if (ht == NULL)
365
        goto end;
366

367
    int r = HashListTableAdd(ht, NULL, 4);
368
    if (r == 0)
369
        goto end;
370

371
    /* all is good! */
372
    result = 1;
373
end:
374
    if (ht != NULL) HashListTableFree(ht);
375
    return result;
376
}
377

378
static int HashListTableTestAdd03 (void)
379
{
380
    int result = 0;
381
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
382
    if (ht == NULL)
383
        goto end;
384

385
    int r = HashListTableAdd(ht, (char *)"test", 0);
386
    if (r != 0)
387
        goto end;
388

389
    if (ht->listhead == NULL) {
390
        printf("ht->listhead == NULL: ");
391
        goto end;
392
    }
393

394
    if (ht->listtail == NULL) {
395
        printf("ht->listtail == NULL: ");
396
        goto end;
397
    }
398

399
    /* all is good! */
400
    result = 1;
401
end:
402
    if (ht != NULL) HashListTableFree(ht);
403
    return result;
404
}
405

406
static int HashListTableTestAdd04 (void)
407
{
408
    int result = 0;
409
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
410
    if (ht == NULL)
411
        goto end;
412

413
    int r = HashListTableAdd(ht, (char *)"test", 4);
414
    if (r != 0)
415
        goto end;
416

417
    char *rp = HashListTableLookup(ht, (char *)"test", 4);
418
    if (rp == NULL)
419
        goto end;
420

421
    HashListTableBucket *htb = HashListTableGetListHead(ht);
422
    if (htb == NULL) {
423
        printf("htb == NULL: ");
424
        goto end;
425
    }
426

427
    char *rp2 = HashListTableGetListData(htb);
428
    if (rp2 == NULL) {
429
        printf("rp2 == NULL: ");
430
        goto end;
431
    }
432

433
    if (rp != rp2) {
434
        printf("rp != rp2: ");
435
        goto end;
436
    }
437

438
    /* all is good! */
439
    result = 1;
440
end:
441
    if (ht != NULL) HashListTableFree(ht);
442
    return result;
443
}
444

445
static int HashListTableTestFull01 (void)
446
{
447
    int result = 0;
448
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
449
    if (ht == NULL)
450
        goto end;
451

452
    int r = HashListTableAdd(ht, (char *)"test", 4);
453
    if (r != 0)
454
        goto end;
455

456
    char *rp = HashListTableLookup(ht, (char *)"test", 4);
457
    if (rp == NULL)
458
        goto end;
459

460
    r = HashListTableRemove(ht, (char *)"test", 4);
461
    if (r != 0)
462
        goto end;
463

464
    /* all is good! */
465
    result = 1;
466
end:
467
    if (ht != NULL) HashListTableFree(ht);
468
    return result;
469
}
470

471
static int HashListTableTestFull02 (void)
472
{
473
    int result = 0;
474
    HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL);
475
    if (ht == NULL)
476
        goto end;
477

478
    int r = HashListTableAdd(ht, (char *)"test", 4);
479
    if (r != 0)
480
        goto end;
481

482
    char *rp = HashListTableLookup(ht, (char *)"test", 4);
483
    if (rp == NULL)
484
        goto end;
485

486
    r = HashListTableRemove(ht, (char *)"test2", 5);
487
    if (r == 0)
488
        goto end;
489

490
    /* all is good! */
491
    result = 1;
492
end:
493
    if (ht != NULL) HashListTableFree(ht);
494
    return result;
495
}
496
#endif /* UNITTESTS */
497

498
void HashListTableRegisterTests(void)
UNCOV
499
{
×
500
#ifdef UNITTESTS
501
    UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01);
502
    UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02);
503
    UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03);
504
    UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04);
505

506
    UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01);
507
    UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02);
508
    UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03);
509
    UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04);
510

511
    UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01);
512
    UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02);
513
#endif /* UNITTESTS */
UNCOV
514
}
×
515

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