Coverage Report

Created: 2026-06-09 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/dict.c
Line
Count
Source
1
#include <string.h>
2
3
#include <import/eb32tree.h>
4
#include <import/ebistree.h>
5
#include <haproxy/dict.h>
6
#include <haproxy/thread.h>
7
8
struct dict *new_dict(const char *name)
9
0
{
10
0
  struct dict *dict;
11
12
0
  dict = malloc(sizeof *dict);
13
0
  if (!dict)
14
0
    return NULL;
15
16
0
  dict->name     = name;
17
0
  dict->values   = EB_ROOT_UNIQUE;
18
0
  HA_RWLOCK_INIT(&dict->rwlock);
19
20
0
  return dict;
21
0
}
22
23
/*
24
 * Allocate a new dictionary entry with <s> as string value which is strdup()'ed.
25
 * Returns the new allocated entry if succeeded, NULL if not.
26
 */
27
static struct dict_entry *new_dict_entry(char *s)
28
0
{
29
0
  struct dict_entry *de;
30
31
0
  de = calloc(1, sizeof *de);
32
0
  if (!de)
33
0
    return NULL;
34
35
0
  de->value.key = strdup(s);
36
0
  if (!de->value.key)
37
0
    goto err;
38
39
0
  de->len = strlen(s);
40
0
  de->refcount = 1;
41
42
0
  return de;
43
44
0
 err:
45
0
  ha_free(&de->value.key);
46
0
  de->len = 0;
47
0
  free(de);
48
0
  return NULL;
49
0
}
50
51
/*
52
 * Release the memory allocated for <de> dictionary entry.
53
 */
54
static void free_dict_entry(struct dict_entry *de)
55
0
{
56
0
  de->refcount = 0;
57
0
  ha_free(&de->value.key);
58
0
  free(de);
59
0
}
60
61
/*
62
 * Simple function to lookup dictionary entries with <s> as key.
63
 */
64
static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
65
0
{
66
0
  struct dict_entry *de;
67
0
  struct ebpt_node *node;
68
69
0
  de = NULL;
70
0
  node = ebis_lookup(&d->values, s);
71
0
  if (node)
72
0
    de = container_of(node, struct dict_entry, value);
73
74
0
  return de;
75
0
}
76
77
/*
78
 * Insert an entry in <d> dictionary with <s> as key.
79
 */
80
struct dict_entry *dict_insert(struct dict *d, char *s)
81
0
{
82
0
  struct dict_entry *de, *tree_de;
83
0
  struct ebpt_node *n;
84
85
0
  HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
86
0
  de = __dict_lookup(d, s);
87
0
  if (de) {
88
0
    HA_ATOMIC_INC(&de->refcount);
89
0
    HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
90
0
    return de;
91
0
  }
92
0
  HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
93
94
0
  de = new_dict_entry(s);
95
0
  if (!de)
96
0
    return NULL;
97
98
0
  HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
99
0
  n = ebis_insert(&d->values, &de->value);
100
0
  tree_de = container_of(n, struct dict_entry, value);
101
0
  if (tree_de == de)
102
0
    HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
103
0
  else {
104
    /* another entry was already there, we'll return it, kill
105
     * ours and bump the other's refcount before returning it.
106
     */
107
0
    HA_ATOMIC_INC(&tree_de->refcount);
108
0
    HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
109
0
    free_dict_entry(de);
110
0
  }
111
0
  return tree_de;
112
0
}
113
114
115
/*
116
 * Unreference a dict entry previously acquired with <dict_insert>.
117
 * If this is the last live reference to the entry, it is
118
 * removed from the dictionary.
119
 */
120
void dict_entry_unref(struct dict *d, struct dict_entry *de)
121
0
{
122
0
  if (!de)
123
0
    return;
124
125
0
  HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
126
0
  if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) {
127
0
    HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
128
0
    return;
129
0
  }
130
0
  ebpt_delete(&de->value);
131
0
  HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
132
133
0
  free_dict_entry(de);
134
0
}