Coverage Report

Created: 2026-08-14 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/stack/stack.cc
Line
Count
Source
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/stack.h>
16
17
#include <assert.h>
18
#include <limits.h>
19
20
#include <algorithm>
21
22
#include <openssl/err.h>
23
#include <openssl/mem.h>
24
25
#include "../internal.h"
26
#include "../mem_internal.h"
27
28
29
using namespace bssl;
30
31
struct stack_st {
32
  // num contains the number of valid pointers in `data`.
33
  size_t num;
34
  void **data;
35
  // sorted is non-zero if the values pointed to by `data` are in ascending
36
  // order, based on `comp`.
37
  int sorted;
38
  // num_alloc contains the number of pointers allocated in the buffer pointed
39
  // to by `data`, which may be larger than `num`.
40
  size_t num_alloc;
41
  // comp is an optional comparison function.
42
  OPENSSL_sk_cmp_func comp;
43
};
44
45
// kMinSize is the number of pointers that will be initially allocated in a new
46
// stack.
47
static const size_t kMinSize = 4;
48
49
885k
OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_cmp_func comp) {
50
885k
  OPENSSL_STACK *ret = New<OPENSSL_STACK>();
51
885k
  if (ret == nullptr) {
52
0
    return nullptr;
53
0
  }
54
55
885k
  ret->data =
56
885k
      reinterpret_cast<void **>(OPENSSL_calloc(kMinSize, sizeof(void *)));
57
885k
  if (ret->data == nullptr) {
58
0
    goto err;
59
0
  }
60
61
885k
  ret->comp = comp;
62
885k
  ret->num_alloc = kMinSize;
63
64
885k
  return ret;
65
66
0
err:
67
0
  Delete(ret);
68
0
  return nullptr;
69
885k
}
70
71
880k
OPENSSL_STACK *OPENSSL_sk_new_null() { return OPENSSL_sk_new(nullptr); }
72
73
3.22M
size_t OPENSSL_sk_num(const OPENSSL_STACK *sk) {
74
3.22M
  if (sk == nullptr) {
75
158k
    return 0;
76
158k
  }
77
3.06M
  return sk->num;
78
3.22M
}
79
80
0
void OPENSSL_sk_zero(OPENSSL_STACK *sk) {
81
0
  if (sk == nullptr || sk->num == 0) {
82
0
    return;
83
0
  }
84
0
  OPENSSL_memset(sk->data, 0, sizeof(void *) * sk->num);
85
0
  sk->num = 0;
86
0
  sk->sorted = 0;
87
0
}
88
89
4.34M
void *OPENSSL_sk_value(const OPENSSL_STACK *sk, size_t i) {
90
4.34M
  if (!sk || i >= sk->num) {
91
0
    return nullptr;
92
0
  }
93
4.34M
  return sk->data[i];
94
4.34M
}
95
96
15.1k
void *OPENSSL_sk_set(OPENSSL_STACK *sk, size_t i, void *value) {
97
15.1k
  if (!sk || i >= sk->num) {
98
0
    return nullptr;
99
0
  }
100
15.1k
  sk->sorted = 0;
101
15.1k
  return sk->data[i] = value;
102
15.1k
}
103
104
1.03M
void OPENSSL_sk_free(OPENSSL_STACK *sk) {
105
1.03M
  if (sk == nullptr) {
106
8.36k
    return;
107
8.36k
  }
108
1.02M
  OPENSSL_free(sk->data);
109
1.02M
  Delete(sk);
110
1.02M
}
111
112
void OPENSSL_sk_pop_free_ex(OPENSSL_STACK *sk,
113
                            OPENSSL_sk_call_free_func call_free_func,
114
2.13M
                            OPENSSL_sk_free_func free_func) {
115
2.13M
  if (sk == nullptr) {
116
1.16M
    return;
117
1.16M
  }
118
119
2.96M
  for (size_t i = 0; i < sk->num; i++) {
120
1.98M
    if (sk->data[i] != nullptr) {
121
1.98M
      call_free_func(free_func, sk->data[i]);
122
1.98M
    }
123
1.98M
  }
124
979k
  OPENSSL_sk_free(sk);
125
979k
}
126
127
// Historically, `sk_pop_free` called the function as `OPENSSL_sk_free_func`
128
// directly. This is undefined in C. Some callers called `sk_pop_free` directly,
129
// so we must maintain a compatibility version for now.
130
0
static void call_free_func_legacy(OPENSSL_sk_free_func func, void *ptr) {
131
0
  func(ptr);
132
0
}
133
134
0
void sk_pop_free(OPENSSL_STACK *sk, OPENSSL_sk_free_func free_func) {
135
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func_legacy, free_func);
136
0
}
137
138
2.11M
size_t OPENSSL_sk_insert(OPENSSL_STACK *sk, void *p, size_t where) {
139
2.11M
  if (sk == nullptr) {
140
0
    return 0;
141
0
  }
142
143
2.11M
  if (sk->num >= INT_MAX) {
144
0
    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
145
0
    return 0;
146
0
  }
147
148
2.11M
  if (sk->num_alloc <= sk->num + 1) {
149
    // Attempt to double the size of the array.
150
116k
    size_t new_alloc = sk->num_alloc << 1;
151
116k
    size_t alloc_size = new_alloc * sizeof(void *);
152
116k
    void **data;
153
154
    // If the doubling overflowed, try to increment.
155
116k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
156
0
      new_alloc = sk->num_alloc + 1;
157
0
      alloc_size = new_alloc * sizeof(void *);
158
0
    }
159
160
    // If the increment also overflowed, fail.
161
116k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
162
0
      return 0;
163
0
    }
164
165
116k
    data = reinterpret_cast<void **>(OPENSSL_realloc(sk->data, alloc_size));
166
116k
    if (data == nullptr) {
167
0
      return 0;
168
0
    }
169
170
116k
    sk->data = data;
171
116k
    sk->num_alloc = new_alloc;
172
116k
  }
173
174
2.11M
  if (where >= sk->num) {
175
2.11M
    sk->data[sk->num] = p;
176
2.11M
  } else {
177
0
    OPENSSL_memmove(&sk->data[where + 1], &sk->data[where],
178
0
                    sizeof(void *) * (sk->num - where));
179
0
    sk->data[where] = p;
180
0
  }
181
182
2.11M
  sk->num++;
183
2.11M
  sk->sorted = 0;
184
185
2.11M
  return sk->num;
186
2.11M
}
187
188
10.9k
void *OPENSSL_sk_delete(OPENSSL_STACK *sk, size_t where) {
189
10.9k
  void *ret;
190
191
10.9k
  if (!sk || where >= sk->num) {
192
0
    return nullptr;
193
0
  }
194
195
10.9k
  ret = sk->data[where];
196
197
10.9k
  if (where != sk->num - 1) {
198
0
    OPENSSL_memmove(&sk->data[where], &sk->data[where + 1],
199
0
                    sizeof(void *) * (sk->num - where - 1));
200
0
  }
201
202
10.9k
  sk->num--;
203
10.9k
  return ret;
204
10.9k
}
205
206
0
void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *sk, const void *p) {
207
0
  if (sk == nullptr) {
208
0
    return nullptr;
209
0
  }
210
211
0
  for (size_t i = 0; i < sk->num; i++) {
212
0
    if (sk->data[i] == p) {
213
0
      return OPENSSL_sk_delete(sk, i);
214
0
    }
215
0
  }
216
217
0
  return nullptr;
218
0
}
219
220
void OPENSSL_sk_delete_if(OPENSSL_STACK *sk,
221
                          OPENSSL_sk_call_delete_if_func call_func,
222
0
                          OPENSSL_sk_delete_if_func func, void *data) {
223
0
  if (sk == nullptr) {
224
0
    return;
225
0
  }
226
227
0
  size_t new_num = 0;
228
0
  for (size_t i = 0; i < sk->num; i++) {
229
0
    if (!call_func(func, sk->data[i], data)) {
230
0
      sk->data[new_num] = sk->data[i];
231
0
      new_num++;
232
0
    }
233
0
  }
234
0
  sk->num = new_num;
235
0
}
236
237
int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, const void *p,
238
51.4k
                    OPENSSL_sk_call_cmp_func call_cmp_func) {
239
51.4k
  if (sk == nullptr) {
240
0
    return 0;
241
0
  }
242
243
51.4k
  if (sk->comp == nullptr) {
244
    // Use pointer equality when no comparison function has been set.
245
344k
    for (size_t i = 0; i < sk->num; i++) {
246
344k
      if (sk->data[i] == p) {
247
51.2k
        if (out_index) {
248
7.77k
          *out_index = i;
249
7.77k
        }
250
51.2k
        return 1;
251
51.2k
      }
252
344k
    }
253
248
    return 0;
254
51.4k
  }
255
256
0
  if (p == nullptr) {
257
0
    return 0;
258
0
  }
259
260
0
  if (!OPENSSL_sk_is_sorted(sk)) {
261
0
    for (size_t i = 0; i < sk->num; i++) {
262
0
      if (call_cmp_func(sk->comp, p, sk->data[i]) == 0) {
263
0
        if (out_index) {
264
0
          *out_index = i;
265
0
        }
266
0
        return 1;
267
0
      }
268
0
    }
269
0
    return 0;
270
0
  }
271
272
  // The stack is sorted, so binary search to find the element.
273
  //
274
  // `lo` and `hi` maintain a half-open interval of where the answer may be. All
275
  // indices such that `lo <= idx < hi` are candidates.
276
0
  size_t lo = 0, hi = sk->num;
277
0
  while (lo < hi) {
278
    // Bias `mid` towards `lo`. See the `r == 0` case below.
279
0
    size_t mid = lo + (hi - lo - 1) / 2;
280
0
    assert(lo <= mid && mid < hi);
281
0
    int r = call_cmp_func(sk->comp, p, sk->data[mid]);
282
0
    if (r > 0) {
283
0
      lo = mid + 1;  // `mid` is too low.
284
0
    } else if (r < 0) {
285
0
      hi = mid;  // `mid` is too high.
286
0
    } else {
287
      // `mid` matches. However, this function returns the earliest match, so we
288
      // can only return if the range has size one.
289
0
      if (hi - lo == 1) {
290
0
        if (out_index != nullptr) {
291
0
          *out_index = mid;
292
0
        }
293
0
        return 1;
294
0
      }
295
      // The sample is biased towards `lo`. `mid` can only be `hi - 1` if
296
      // `hi - lo` was one, so this makes forward progress.
297
0
      assert(mid + 1 < hi);
298
0
      hi = mid + 1;
299
0
    }
300
0
  }
301
302
0
  assert(lo == hi);
303
0
  return 0;  // Not found.
304
0
}
305
306
0
void *OPENSSL_sk_shift(OPENSSL_STACK *sk) {
307
0
  if (sk == nullptr) {
308
0
    return nullptr;
309
0
  }
310
0
  if (sk->num == 0) {
311
0
    return nullptr;
312
0
  }
313
0
  return OPENSSL_sk_delete(sk, 0);
314
0
}
315
316
2.11M
size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p) {
317
2.11M
  return OPENSSL_sk_insert(sk, p, sk->num);
318
2.11M
}
319
320
10.9k
void *OPENSSL_sk_pop(OPENSSL_STACK *sk) {
321
10.9k
  if (sk == nullptr) {
322
0
    return nullptr;
323
0
  }
324
10.9k
  if (sk->num == 0) {
325
0
    return nullptr;
326
0
  }
327
10.9k
  return OPENSSL_sk_delete(sk, sk->num - 1);
328
10.9k
}
329
330
140k
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk) {
331
140k
  if (sk == nullptr) {
332
0
    return nullptr;
333
0
  }
334
335
140k
  OPENSSL_STACK *ret = New<OPENSSL_STACK>();
336
140k
  if (ret == nullptr) {
337
0
    return nullptr;
338
0
  }
339
340
140k
  ret->data = reinterpret_cast<void **>(
341
140k
      OPENSSL_memdup(sk->data, sizeof(void *) * sk->num_alloc));
342
140k
  if (ret->data == nullptr) {
343
0
    goto err;
344
0
  }
345
346
140k
  ret->num = sk->num;
347
140k
  ret->sorted = sk->sorted;
348
140k
  ret->num_alloc = sk->num_alloc;
349
140k
  ret->comp = sk->comp;
350
140k
  return ret;
351
352
0
err:
353
0
  OPENSSL_sk_free(ret);
354
0
  return nullptr;
355
140k
}
356
357
void OPENSSL_sk_sort(OPENSSL_STACK *sk,
358
0
                     OPENSSL_sk_call_cmp_func call_cmp_func) {
359
0
  if (sk == nullptr || sk->comp == nullptr || sk->sorted) {
360
0
    return;
361
0
  }
362
363
0
  std::sort(sk->data, sk->data + sk->num, [&](void *a, void *b) {
364
0
    return call_cmp_func(sk->comp, a, b) < 0;
365
0
  });
366
0
  sk->sorted = 1;
367
0
}
368
369
void OPENSSL_sk_sort_and_dedup(
370
    OPENSSL_STACK *sk, OPENSSL_sk_call_cmp_func call_cmp_func,
371
0
    OPENSSL_sk_call_free_func call_free_func, OPENSSL_sk_free_func free_func) {
372
0
  OPENSSL_sk_sort(sk, call_cmp_func);
373
0
  if (sk == nullptr || sk->comp == nullptr || sk->num <= 1) {
374
0
    return;
375
0
  }
376
377
0
  size_t new_num = 1;
378
0
  for (size_t i = 1; i < sk->num; i++) {
379
0
    if (call_cmp_func(sk->comp, sk->data[i], sk->data[new_num - 1]) != 0) {
380
0
      sk->data[new_num] = sk->data[i];
381
0
      new_num++;
382
0
    } else if (free_func != nullptr) {
383
0
      call_free_func(free_func, sk->data[i]);
384
0
    }
385
0
  }
386
0
  sk->num = new_num;
387
0
}
388
389
0
int OPENSSL_sk_is_sorted(const OPENSSL_STACK *sk) {
390
0
  if (!sk) {
391
0
    return 1;
392
0
  }
393
  // Zero- and one-element lists are always sorted.
394
0
  return sk->sorted || (sk->comp != nullptr && sk->num < 2);
395
0
}
396
397
OPENSSL_sk_cmp_func OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk,
398
0
                                            OPENSSL_sk_cmp_func comp) {
399
0
  OPENSSL_sk_cmp_func old = sk->comp;
400
401
0
  if (sk->comp != comp) {
402
0
    sk->sorted = 0;
403
0
  }
404
0
  sk->comp = comp;
405
406
0
  return old;
407
0
}
408
409
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
410
                                    OPENSSL_sk_call_copy_func call_copy_func,
411
                                    OPENSSL_sk_copy_func copy_func,
412
                                    OPENSSL_sk_call_free_func call_free_func,
413
140k
                                    OPENSSL_sk_free_func free_func) {
414
140k
  OPENSSL_STACK *ret = OPENSSL_sk_dup(sk);
415
140k
  if (ret == nullptr) {
416
0
    return nullptr;
417
0
  }
418
419
285k
  for (size_t i = 0; i < ret->num; i++) {
420
145k
    if (ret->data[i] == nullptr) {
421
355
      continue;
422
355
    }
423
145k
    ret->data[i] = call_copy_func(copy_func, ret->data[i]);
424
145k
    if (ret->data[i] == nullptr) {
425
0
      for (size_t j = 0; j < i; j++) {
426
0
        if (ret->data[j] != nullptr) {
427
0
          call_free_func(free_func, ret->data[j]);
428
0
        }
429
0
      }
430
0
      OPENSSL_sk_free(ret);
431
0
      return nullptr;
432
0
    }
433
145k
  }
434
435
140k
  return ret;
436
140k
}
437
438
0
OPENSSL_STACK *sk_new_null() { return OPENSSL_sk_new_null(); }
439
440
0
size_t sk_num(const OPENSSL_STACK *sk) { return OPENSSL_sk_num(sk); }
441
442
0
void *sk_value(const OPENSSL_STACK *sk, size_t i) {
443
0
  return OPENSSL_sk_value(sk, i);
444
0
}
445
446
0
void sk_free(OPENSSL_STACK *sk) { OPENSSL_sk_free(sk); }
447
448
0
size_t sk_push(OPENSSL_STACK *sk, void *p) { return OPENSSL_sk_push(sk, p); }
449
450
0
void *sk_pop(OPENSSL_STACK *sk) { return OPENSSL_sk_pop(sk); }
451
452
void sk_pop_free_ex(OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func,
453
0
                    OPENSSL_sk_free_func free_func) {
454
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func, free_func);
455
0
}