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

c-ares / c-ares / 14322798410

08 Apr 2025 01:08AM UTC coverage: 91.484% (-0.008%) from 91.492%
14322798410

push

github

bradh352
Fix polling ares_event_configchg_init: initialize mutex (#974)

The polling-based implementation of ares_event_configchg_init previously
did not initialize the mutex ares_event_configchg_t->lock. This caused
ares_thread_cond_timedwait to immediately return, which means that the
thread running ares_event_configchg_thread is busy-waiting without
sleeping between config change checks. In addition to the high CPU usage
this causes, the DNS config is actually never checked in this case.

This commit fixes the issue by initializing the mutex. Thereby, the
config polling thread correctly only wakes up every 30 seconds and
properly checks for a config change.

Note: the bug only came into effect if the combination of the polling-
based implementation of ares_event_configchg_init and the pthread-based
implementation of ares_thread_cond_timedwait was used.

Fix By: Florian Pfisterer (@FlorianPfisterer)

22399 of 24484 relevant lines covered (91.48%)

11828.47 hits per line

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

86.67
/src/lib/dsa/ares_array.c
1
/* MIT License
2
 *
3
 * Copyright (c) 2024 Brad House
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining a copy
6
 * of this software and associated documentation files (the "Software"), to deal
7
 * in the Software without restriction, including without limitation the rights
8
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the Software is
10
 * furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice (including the next
13
 * paragraph) shall be included in all copies or substantial portions of the
14
 * Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 *
24
 * SPDX-License-Identifier: MIT
25
 */
26
#include "ares_private.h"
27
#include "ares_array.h"
28

29
#define ARES__ARRAY_MIN 4
30

31
struct ares_array {
32
  ares_array_destructor_t destruct;
33
  void                   *arr;
34
  size_t                  member_size;
35
  size_t                  cnt;
36
  size_t                  offset;
37
  size_t                  alloc_cnt;
38
};
39

40
ares_array_t *ares_array_create(size_t                  member_size,
126,101✔
41
                                ares_array_destructor_t destruct)
42
{
43
  ares_array_t *arr;
44

45
  if (member_size == 0) {
126,101✔
46
    return NULL;
1✔
47
  }
48

49
  arr = ares_malloc_zero(sizeof(*arr));
126,100✔
50
  if (arr == NULL) {
126,100✔
51
    return NULL;
46✔
52
  }
53

54
  arr->member_size = member_size;
126,054✔
55
  arr->destruct    = destruct;
126,054✔
56
  return arr;
126,054✔
57
}
58

59
size_t ares_array_len(const ares_array_t *arr)
614,721✔
60
{
61
  if (arr == NULL) {
614,721✔
62
    return 0;
6✔
63
  }
64
  return arr->cnt;
614,715✔
65
}
66

67
void *ares_array_at(ares_array_t *arr, size_t idx)
345,424✔
68
{
69
  if (arr == NULL || idx >= arr->cnt) {
345,424✔
70
    return NULL;
5✔
71
  }
72
  return (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size);
345,419✔
73
}
74

75
const void *ares_array_at_const(const ares_array_t *arr, size_t idx)
77✔
76
{
77
  if (arr == NULL || idx >= arr->cnt) {
77✔
78
    return NULL;
5✔
79
  }
80
  return (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size);
72✔
81
}
82

83
ares_status_t ares_array_sort(ares_array_t *arr, ares_array_cmp_t cmp)
3✔
84
{
85
  if (arr == NULL || cmp == NULL) {
3✔
86
    return ARES_EFORMERR;
1✔
87
  }
88

89
  /* Nothing to sort */
90
  if (arr->cnt < 2) {
2✔
91
    return ARES_SUCCESS;
1✔
92
  }
93

94
  qsort((unsigned char *)arr->arr + (arr->offset * arr->member_size), arr->cnt,
1✔
95
        arr->member_size, cmp);
96
  return ARES_SUCCESS;
1✔
97
}
98

99
void ares_array_destroy(ares_array_t *arr)
116,819✔
100
{
101
  size_t i;
102

103
  if (arr == NULL) {
116,819✔
104
    return;
4,686✔
105
  }
106

107
  if (arr->destruct != NULL) {
112,133✔
108
    for (i = 0; i < arr->cnt; i++) {
250,139✔
109
      arr->destruct(ares_array_at(arr, i));
138,004✔
110
    }
111
  }
112

113
  ares_free(arr->arr);
112,133✔
114
  ares_free(arr);
112,131✔
115
}
116

117
/* NOTE: this function operates on actual indexes, NOT indexes using the
118
 *       arr->offset */
119
static ares_status_t ares_array_move(ares_array_t *arr, size_t dest_idx,
10✔
120
                                     size_t src_idx)
121
{
122
  void       *dest_ptr;
123
  const void *src_ptr;
124
  size_t      nmembers;
125

126
  if (arr == NULL || dest_idx >= arr->alloc_cnt || src_idx >= arr->alloc_cnt) {
10✔
127
    return ARES_EFORMERR;
×
128
  }
129

130
  /* Nothing to do */
131
  if (dest_idx == src_idx) {
10✔
132
    return ARES_SUCCESS;
×
133
  }
134

135
  dest_ptr = (unsigned char *)arr->arr + (dest_idx * arr->member_size);
10✔
136
  src_ptr  = (unsigned char *)arr->arr + (src_idx * arr->member_size);
10✔
137

138
  /* Check to make sure shifting to the right won't overflow our allocation
139
   * boundary */
140
  if (dest_idx > src_idx && arr->cnt + (dest_idx - src_idx) > arr->alloc_cnt) {
10✔
141
    return ARES_EFORMERR;
×
142
  }
143

144
  nmembers = arr->cnt - (src_idx - arr->offset);
10✔
145
  memmove(dest_ptr, src_ptr, nmembers * arr->member_size);
10✔
146

147
  return ARES_SUCCESS;
10✔
148
}
149

150
void *ares_array_finish(ares_array_t *arr, size_t *num_members)
13,919✔
151
{
152
  void *ptr;
153

154
  if (arr == NULL || num_members == NULL) {
13,919✔
155
    return NULL;
1✔
156
  }
157

158
  /* Make sure we move data to beginning of allocation */
159
  if (arr->offset != 0) {
13,918✔
160
    if (ares_array_move(arr, 0, arr->offset) != ARES_SUCCESS) {
×
161
      return NULL;
×
162
    }
163
    arr->offset = 0;
×
164
  }
165

166
  ptr          = arr->arr;
13,918✔
167
  *num_members = arr->cnt;
13,918✔
168
  ares_free(arr);
13,918✔
169
  return ptr;
13,918✔
170
}
171

172
ares_status_t ares_array_set_size(ares_array_t *arr, size_t size)
171,553✔
173
{
174
  void *temp;
175

176
  if (arr == NULL || size == 0 || size < arr->cnt) {
171,553✔
177
    return ARES_EFORMERR;
×
178
  }
179

180
  /* Always operate on powers of 2 */
181
  size = ares_round_up_pow2(size);
171,553✔
182

183
  if (size < ARES__ARRAY_MIN) {
171,551✔
184
    size = ARES__ARRAY_MIN;
118,201✔
185
  }
186

187
  /* If our allocation size is already large enough, skip */
188
  if (size <= arr->alloc_cnt) {
171,551✔
189
    return ARES_SUCCESS;
82,903✔
190
  }
191

192
  temp = ares_realloc_zero(arr->arr, arr->alloc_cnt * arr->member_size,
88,648✔
193
                           size * arr->member_size);
88,648✔
194
  if (temp == NULL) {
88,650✔
195
    return ARES_ENOMEM;
12✔
196
  }
197
  arr->alloc_cnt = size;
88,638✔
198
  arr->arr       = temp;
88,638✔
199
  return ARES_SUCCESS;
88,638✔
200
}
201

202
ares_status_t ares_array_insert_at(void **elem_ptr, ares_array_t *arr,
164,250✔
203
                                   size_t idx)
204
{
205
  void         *ptr;
206
  ares_status_t status;
207

208
  if (arr == NULL) {
164,250✔
209
    return ARES_EFORMERR;
6✔
210
  }
211

212
  /* Not >= since we are allowed to append to the end */
213
  if (idx > arr->cnt) {
164,244✔
214
    return ARES_EFORMERR;
1✔
215
  }
216

217
  /* Allocate more if needed */
218
  status = ares_array_set_size(arr, arr->cnt + 1);
164,243✔
219
  if (status != ARES_SUCCESS) {
164,245✔
220
    return status;
5✔
221
  }
222

223
  /* Shift if we have memory but not enough room at the end */
224
  if (arr->cnt + 1 + arr->offset > arr->alloc_cnt) {
164,240✔
225
    status = ares_array_move(arr, 0, arr->offset);
1✔
226
    if (status != ARES_SUCCESS) {
1✔
227
      return status;
×
228
    }
229
    arr->offset = 0;
1✔
230
  }
231

232
  /* If we're inserting anywhere other than the end, we need to move some
233
   * elements out of the way */
234
  if (idx != arr->cnt) {
164,240✔
235
    status = ares_array_move(arr, idx + arr->offset + 1, idx + arr->offset);
2✔
236
    if (status != ARES_SUCCESS) {
2✔
237
      return status;
×
238
    }
239
  }
240

241
  /* Ok, we're guaranteed to have a gap where we need it, lets zero it out,
242
   * and return it */
243
  ptr = (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size);
164,240✔
244
  memset(ptr, 0, arr->member_size);
164,240✔
245
  arr->cnt++;
164,240✔
246

247
  if (elem_ptr) {
164,240✔
248
    *elem_ptr = ptr;
164,240✔
249
  }
250

251
  return ARES_SUCCESS;
164,240✔
252
}
253

254
ares_status_t ares_array_insert_last(void **elem_ptr, ares_array_t *arr)
164,246✔
255
{
256
  return ares_array_insert_at(elem_ptr, arr, ares_array_len(arr));
164,246✔
257
}
258

259
ares_status_t ares_array_insert_first(void **elem_ptr, ares_array_t *arr)
1✔
260
{
261
  return ares_array_insert_at(elem_ptr, arr, 0);
1✔
262
}
263

264
ares_status_t ares_array_insertdata_at(ares_array_t *arr, size_t idx,
1✔
265
                                       const void *data_ptr)
266
{
267
  ares_status_t status;
268
  void         *ptr = NULL;
1✔
269

270
  status = ares_array_insert_at(&ptr, arr, idx);
1✔
271
  if (status != ARES_SUCCESS) {
1✔
272
    return status;
1✔
273
  }
274
  memcpy(ptr, data_ptr, arr->member_size);
×
275
  return ARES_SUCCESS;
×
276
}
277

278
ares_status_t ares_array_insertdata_last(ares_array_t *arr,
78,957✔
279
                                         const void   *data_ptr)
280
{
281
  ares_status_t status;
282
  void         *ptr = NULL;
78,957✔
283

284
  status = ares_array_insert_last(&ptr, arr);
78,957✔
285
  if (status != ARES_SUCCESS) {
78,957✔
286
    return status;
2✔
287
  }
288
  memcpy(ptr, data_ptr, arr->member_size);
78,955✔
289
  return ARES_SUCCESS;
78,955✔
290
}
291

292
ares_status_t ares_array_insertdata_first(ares_array_t *arr,
1✔
293
                                          const void   *data_ptr)
294
{
295
  ares_status_t status;
296
  void         *ptr = NULL;
1✔
297

298
  status = ares_array_insert_last(&ptr, arr);
1✔
299
  if (status != ARES_SUCCESS) {
1✔
300
    return status;
1✔
301
  }
302
  memcpy(ptr, data_ptr, arr->member_size);
×
303
  return ARES_SUCCESS;
×
304
}
305

306
void *ares_array_first(ares_array_t *arr)
2✔
307
{
308
  return ares_array_at(arr, 0);
2✔
309
}
310

311
void *ares_array_last(ares_array_t *arr)
17,938✔
312
{
313
  size_t cnt = ares_array_len(arr);
17,938✔
314
  if (cnt == 0) {
17,938✔
315
    return NULL;
1✔
316
  }
317
  return ares_array_at(arr, cnt - 1);
17,937✔
318
}
319

320
const void *ares_array_first_const(const ares_array_t *arr)
×
321
{
322
  return ares_array_at_const(arr, 0);
×
323
}
324

325
const void *ares_array_last_const(const ares_array_t *arr)
×
326
{
327
  size_t cnt = ares_array_len(arr);
×
328
  if (cnt == 0) {
×
329
    return NULL;
×
330
  }
331
  return ares_array_at_const(arr, cnt - 1);
×
332
}
333

334
ares_status_t ares_array_claim_at(void *dest, size_t dest_size,
10,971✔
335
                                  ares_array_t *arr, size_t idx)
336
{
337
  ares_status_t status;
338

339
  if (arr == NULL || idx >= arr->cnt) {
10,971✔
340
    return ARES_EFORMERR;
1✔
341
  }
342

343
  if (dest != NULL && dest_size < arr->member_size) {
10,970✔
344
    return ARES_EFORMERR;
×
345
  }
346

347
  if (dest) {
10,970✔
348
    memcpy(dest, ares_array_at(arr, idx), arr->member_size);
1✔
349
  }
350

351
  if (idx == 0) {
10,970✔
352
    /* Optimization, if first element, just increment offset, makes removing a
353
     * lot from the start quick */
354
    arr->offset++;
6,416✔
355
  } else if (idx != arr->cnt - 1) {
4,554✔
356
    /* Must shift entire array if removing an element from the middle. Does
357
     * nothing if removing last element other than decrement count. */
358
    status = ares_array_move(arr, idx + arr->offset, idx + arr->offset + 1);
7✔
359
    if (status != ARES_SUCCESS) {
7✔
360
      return status;
×
361
    }
362
  }
363

364
  arr->cnt--;
10,970✔
365
  return ARES_SUCCESS;
10,970✔
366
}
367

368
ares_status_t ares_array_remove_at(ares_array_t *arr, size_t idx)
10,971✔
369
{
370
  void *ptr = ares_array_at(arr, idx);
10,971✔
371
  if (arr == NULL || ptr == NULL) {
10,971✔
372
    return ARES_EFORMERR;
2✔
373
  }
374

375
  if (arr->destruct != NULL) {
10,969✔
376
    arr->destruct(ptr);
10,969✔
377
  }
378

379
  return ares_array_claim_at(NULL, 0, arr, idx);
10,969✔
380
}
381

382
ares_status_t ares_array_remove_first(ares_array_t *arr)
3✔
383
{
384
  return ares_array_remove_at(arr, 0);
3✔
385
}
386

387
ares_status_t ares_array_remove_last(ares_array_t *arr)
10,889✔
388
{
389
  size_t cnt = ares_array_len(arr);
10,889✔
390
  if (cnt == 0) {
10,889✔
391
    return ARES_EFORMERR;
1✔
392
  }
393
  return ares_array_remove_at(arr, cnt - 1);
10,888✔
394
}
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

© 2025 Coveralls, Inc