Coverage Report

Created: 2026-02-16 07:12

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 <openssl/err.h>
21
#include <openssl/mem.h>
22
23
#include "../internal.h"
24
#include "../mem_internal.h"
25
26
27
using namespace bssl;
28
29
struct stack_st {
30
  // num contains the number of valid pointers in |data|.
31
  size_t num;
32
  void **data;
33
  // sorted is non-zero if the values pointed to by |data| are in ascending
34
  // order, based on |comp|.
35
  int sorted;
36
  // num_alloc contains the number of pointers allocated in the buffer pointed
37
  // to by |data|, which may be larger than |num|.
38
  size_t num_alloc;
39
  // comp is an optional comparison function.
40
  OPENSSL_sk_cmp_func comp;
41
};
42
43
// kMinSize is the number of pointers that will be initially allocated in a new
44
// stack.
45
static const size_t kMinSize = 4;
46
47
953k
OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_cmp_func comp) {
48
953k
  OPENSSL_STACK *ret = NewZeroed<OPENSSL_STACK>();
49
953k
  if (ret == nullptr) {
50
0
    return nullptr;
51
0
  }
52
53
953k
  ret->data =
54
953k
      reinterpret_cast<void **>(OPENSSL_calloc(kMinSize, sizeof(void *)));
55
953k
  if (ret->data == nullptr) {
56
0
    goto err;
57
0
  }
58
59
953k
  ret->comp = comp;
60
953k
  ret->num_alloc = kMinSize;
61
62
953k
  return ret;
63
64
0
err:
65
0
  Delete(ret);
66
0
  return nullptr;
67
953k
}
68
69
949k
OPENSSL_STACK *OPENSSL_sk_new_null() { return OPENSSL_sk_new(nullptr); }
70
71
5.91M
size_t OPENSSL_sk_num(const OPENSSL_STACK *sk) {
72
5.91M
  if (sk == nullptr) {
73
586k
    return 0;
74
586k
  }
75
5.33M
  return sk->num;
76
5.91M
}
77
78
0
void OPENSSL_sk_zero(OPENSSL_STACK *sk) {
79
0
  if (sk == nullptr || sk->num == 0) {
80
0
    return;
81
0
  }
82
0
  OPENSSL_memset(sk->data, 0, sizeof(void *) * sk->num);
83
0
  sk->num = 0;
84
0
  sk->sorted = 0;
85
0
}
86
87
5.80M
void *OPENSSL_sk_value(const OPENSSL_STACK *sk, size_t i) {
88
5.80M
  if (!sk || i >= sk->num) {
89
0
    return nullptr;
90
0
  }
91
5.80M
  return sk->data[i];
92
5.80M
}
93
94
185k
void *OPENSSL_sk_set(OPENSSL_STACK *sk, size_t i, void *value) {
95
185k
  if (!sk || i >= sk->num) {
96
0
    return nullptr;
97
0
  }
98
185k
  return sk->data[i] = value;
99
185k
}
100
101
1.58M
void OPENSSL_sk_free(OPENSSL_STACK *sk) {
102
1.58M
  if (sk == nullptr) {
103
439k
    return;
104
439k
  }
105
1.14M
  OPENSSL_free(sk->data);
106
1.14M
  Delete(sk);
107
1.14M
}
108
109
void OPENSSL_sk_pop_free_ex(OPENSSL_STACK *sk,
110
                            OPENSSL_sk_call_free_func call_free_func,
111
2.80M
                            OPENSSL_sk_free_func free_func) {
112
2.80M
  if (sk == nullptr) {
113
1.78M
    return;
114
1.78M
  }
115
116
3.02M
  for (size_t i = 0; i < sk->num; i++) {
117
2.00M
    if (sk->data[i] != nullptr) {
118
2.00M
      call_free_func(free_func, sk->data[i]);
119
2.00M
    }
120
2.00M
  }
121
1.01M
  OPENSSL_sk_free(sk);
122
1.01M
}
123
124
// Historically, |sk_pop_free| called the function as |OPENSSL_sk_free_func|
125
// directly. This is undefined in C. Some callers called |sk_pop_free| directly,
126
// so we must maintain a compatibility version for now.
127
0
static void call_free_func_legacy(OPENSSL_sk_free_func func, void *ptr) {
128
0
  func(ptr);
129
0
}
130
131
0
void sk_pop_free(OPENSSL_STACK *sk, OPENSSL_sk_free_func free_func) {
132
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func_legacy, free_func);
133
0
}
134
135
2.52M
size_t OPENSSL_sk_insert(OPENSSL_STACK *sk, void *p, size_t where) {
136
2.52M
  if (sk == nullptr) {
137
0
    return 0;
138
0
  }
139
140
2.52M
  if (sk->num >= INT_MAX) {
141
0
    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
142
0
    return 0;
143
0
  }
144
145
2.52M
  if (sk->num_alloc <= sk->num + 1) {
146
    // Attempt to double the size of the array.
147
111k
    size_t new_alloc = sk->num_alloc << 1;
148
111k
    size_t alloc_size = new_alloc * sizeof(void *);
149
111k
    void **data;
150
151
    // If the doubling overflowed, try to increment.
152
111k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
153
0
      new_alloc = sk->num_alloc + 1;
154
0
      alloc_size = new_alloc * sizeof(void *);
155
0
    }
156
157
    // If the increment also overflowed, fail.
158
111k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
159
0
      return 0;
160
0
    }
161
162
111k
    data = reinterpret_cast<void **>(OPENSSL_realloc(sk->data, alloc_size));
163
111k
    if (data == nullptr) {
164
0
      return 0;
165
0
    }
166
167
111k
    sk->data = data;
168
111k
    sk->num_alloc = new_alloc;
169
111k
  }
170
171
2.52M
  if (where >= sk->num) {
172
2.52M
    sk->data[sk->num] = p;
173
2.52M
  } else {
174
0
    OPENSSL_memmove(&sk->data[where + 1], &sk->data[where],
175
0
                    sizeof(void *) * (sk->num - where));
176
0
    sk->data[where] = p;
177
0
  }
178
179
2.52M
  sk->num++;
180
2.52M
  sk->sorted = 0;
181
182
2.52M
  return sk->num;
183
2.52M
}
184
185
9.73k
void *OPENSSL_sk_delete(OPENSSL_STACK *sk, size_t where) {
186
9.73k
  void *ret;
187
188
9.73k
  if (!sk || where >= sk->num) {
189
0
    return nullptr;
190
0
  }
191
192
9.73k
  ret = sk->data[where];
193
194
9.73k
  if (where != sk->num - 1) {
195
4.02k
    OPENSSL_memmove(&sk->data[where], &sk->data[where + 1],
196
4.02k
                    sizeof(void *) * (sk->num - where - 1));
197
4.02k
  }
198
199
9.73k
  sk->num--;
200
9.73k
  return ret;
201
9.73k
}
202
203
4.02k
void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *sk, const void *p) {
204
4.02k
  if (sk == nullptr) {
205
0
    return nullptr;
206
0
  }
207
208
16.9k
  for (size_t i = 0; i < sk->num; i++) {
209
16.9k
    if (sk->data[i] == p) {
210
4.02k
      return OPENSSL_sk_delete(sk, i);
211
4.02k
    }
212
16.9k
  }
213
214
0
  return nullptr;
215
4.02k
}
216
217
void OPENSSL_sk_delete_if(OPENSSL_STACK *sk,
218
                          OPENSSL_sk_call_delete_if_func call_func,
219
0
                          OPENSSL_sk_delete_if_func func, void *data) {
220
0
  if (sk == nullptr) {
221
0
    return;
222
0
  }
223
224
0
  size_t new_num = 0;
225
0
  for (size_t i = 0; i < sk->num; i++) {
226
0
    if (!call_func(func, sk->data[i], data)) {
227
0
      sk->data[new_num] = sk->data[i];
228
0
      new_num++;
229
0
    }
230
0
  }
231
0
  sk->num = new_num;
232
0
}
233
234
int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, const void *p,
235
47.0k
                    OPENSSL_sk_call_cmp_func call_cmp_func) {
236
47.0k
  if (sk == nullptr) {
237
0
    return 0;
238
0
  }
239
240
47.0k
  if (sk->comp == nullptr) {
241
    // Use pointer equality when no comparison function has been set.
242
359k
    for (size_t i = 0; i < sk->num; i++) {
243
359k
      if (sk->data[i] == p) {
244
46.8k
        if (out_index) {
245
7.22k
          *out_index = i;
246
7.22k
        }
247
46.8k
        return 1;
248
46.8k
      }
249
359k
    }
250
204
    return 0;
251
47.0k
  }
252
253
0
  if (p == nullptr) {
254
0
    return 0;
255
0
  }
256
257
0
  if (!OPENSSL_sk_is_sorted(sk)) {
258
0
    for (size_t i = 0; i < sk->num; i++) {
259
0
      if (call_cmp_func(sk->comp, p, sk->data[i]) == 0) {
260
0
        if (out_index) {
261
0
          *out_index = i;
262
0
        }
263
0
        return 1;
264
0
      }
265
0
    }
266
0
    return 0;
267
0
  }
268
269
  // The stack is sorted, so binary search to find the element.
270
  //
271
  // |lo| and |hi| maintain a half-open interval of where the answer may be. All
272
  // indices such that |lo <= idx < hi| are candidates.
273
0
  size_t lo = 0, hi = sk->num;
274
0
  while (lo < hi) {
275
    // Bias |mid| towards |lo|. See the |r == 0| case below.
276
0
    size_t mid = lo + (hi - lo - 1) / 2;
277
0
    assert(lo <= mid && mid < hi);
278
0
    int r = call_cmp_func(sk->comp, p, sk->data[mid]);
279
0
    if (r > 0) {
280
0
      lo = mid + 1;  // |mid| is too low.
281
0
    } else if (r < 0) {
282
0
      hi = mid;  // |mid| is too high.
283
0
    } else {
284
      // |mid| matches. However, this function returns the earliest match, so we
285
      // can only return if the range has size one.
286
0
      if (hi - lo == 1) {
287
0
        if (out_index != nullptr) {
288
0
          *out_index = mid;
289
0
        }
290
0
        return 1;
291
0
      }
292
      // The sample is biased towards |lo|. |mid| can only be |hi - 1| if
293
      // |hi - lo| was one, so this makes forward progress.
294
0
      assert(mid + 1 < hi);
295
0
      hi = mid + 1;
296
0
    }
297
0
  }
298
299
0
  assert(lo == hi);
300
0
  return 0;  // Not found.
301
0
}
302
303
0
void *OPENSSL_sk_shift(OPENSSL_STACK *sk) {
304
0
  if (sk == nullptr) {
305
0
    return nullptr;
306
0
  }
307
0
  if (sk->num == 0) {
308
0
    return nullptr;
309
0
  }
310
0
  return OPENSSL_sk_delete(sk, 0);
311
0
}
312
313
2.50M
size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p) {
314
2.50M
  return OPENSSL_sk_insert(sk, p, sk->num);
315
2.50M
}
316
317
5.70k
void *OPENSSL_sk_pop(OPENSSL_STACK *sk) {
318
5.70k
  if (sk == nullptr) {
319
0
    return nullptr;
320
0
  }
321
5.70k
  if (sk->num == 0) {
322
0
    return nullptr;
323
0
  }
324
5.70k
  return OPENSSL_sk_delete(sk, sk->num - 1);
325
5.70k
}
326
327
187k
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk) {
328
187k
  if (sk == nullptr) {
329
0
    return nullptr;
330
0
  }
331
332
187k
  OPENSSL_STACK *ret = NewZeroed<OPENSSL_STACK>();
333
187k
  if (ret == nullptr) {
334
0
    return nullptr;
335
0
  }
336
337
187k
  ret->data = reinterpret_cast<void **>(
338
187k
      OPENSSL_memdup(sk->data, sizeof(void *) * sk->num_alloc));
339
187k
  if (ret->data == nullptr) {
340
0
    goto err;
341
0
  }
342
343
187k
  ret->num = sk->num;
344
187k
  ret->sorted = sk->sorted;
345
187k
  ret->num_alloc = sk->num_alloc;
346
187k
  ret->comp = sk->comp;
347
187k
  return ret;
348
349
0
err:
350
0
  OPENSSL_sk_free(ret);
351
0
  return nullptr;
352
187k
}
353
354
0
static size_t parent_idx(size_t idx) {
355
0
  assert(idx > 0);
356
0
  return (idx - 1) / 2;
357
0
}
358
359
0
static size_t left_idx(size_t idx) {
360
  // The largest possible index is |PTRDIFF_MAX|, not |SIZE_MAX|. If
361
  // |ptrdiff_t|, a signed type, is the same size as |size_t|, this cannot
362
  // overflow.
363
0
  assert(idx <= PTRDIFF_MAX);
364
0
  static_assert(PTRDIFF_MAX <= (SIZE_MAX - 1) / 2, "2 * idx + 1 may overflow");
365
0
  return 2 * idx + 1;
366
0
}
367
368
// down_heap fixes the subtree rooted at |i|. |i|'s children must each satisfy
369
// the heap property. Only the first |num| elements of |sk| are considered.
370
static void down_heap(OPENSSL_STACK *sk, OPENSSL_sk_call_cmp_func call_cmp_func,
371
0
                      size_t i, size_t num) {
372
0
  assert(i < num && num <= sk->num);
373
0
  for (;;) {
374
0
    size_t left = left_idx(i);
375
0
    if (left >= num) {
376
0
      break;  // No left child.
377
0
    }
378
379
    // Swap |i| with the largest of its children.
380
0
    size_t next = i;
381
0
    if (call_cmp_func(sk->comp, sk->data[next], sk->data[left]) < 0) {
382
0
      next = left;
383
0
    }
384
0
    size_t right = left + 1;  // Cannot overflow because |left < num|.
385
0
    if (right < num &&
386
0
        call_cmp_func(sk->comp, sk->data[next], sk->data[right]) < 0) {
387
0
      next = right;
388
0
    }
389
390
0
    if (i == next) {
391
0
      break;  // |i| is already larger than its children.
392
0
    }
393
394
0
    void *tmp = sk->data[i];
395
0
    sk->data[i] = sk->data[next];
396
0
    sk->data[next] = tmp;
397
0
    i = next;
398
0
  }
399
0
}
400
401
void OPENSSL_sk_sort(OPENSSL_STACK *sk,
402
0
                     OPENSSL_sk_call_cmp_func call_cmp_func) {
403
0
  if (sk == nullptr || sk->comp == nullptr || sk->sorted) {
404
0
    return;
405
0
  }
406
407
0
  if (sk->num >= 2) {
408
    // |qsort| lacks a context parameter in the comparison function for us to
409
    // pass in |call_cmp_func| and |sk->comp|. While we could cast |sk->comp| to
410
    // the expected type, it is undefined behavior in C can trip sanitizers.
411
    // |qsort_r| and |qsort_s| avoid this, but using them is impractical. See
412
    // https://stackoverflow.com/a/39561369
413
    //
414
    // Use our own heap sort instead. This is not performance-sensitive, so we
415
    // optimize for simplicity and size. First, build a max-heap in place.
416
0
    for (size_t i = parent_idx(sk->num - 1); i < sk->num; i--) {
417
0
      down_heap(sk, call_cmp_func, i, sk->num);
418
0
    }
419
420
    // Iteratively remove the maximum element to populate the result in reverse.
421
0
    for (size_t i = sk->num - 1; i > 0; i--) {
422
0
      void *tmp = sk->data[0];
423
0
      sk->data[0] = sk->data[i];
424
0
      sk->data[i] = tmp;
425
0
      down_heap(sk, call_cmp_func, 0, i);
426
0
    }
427
0
  }
428
0
  sk->sorted = 1;
429
0
}
430
431
0
int OPENSSL_sk_is_sorted(const OPENSSL_STACK *sk) {
432
0
  if (!sk) {
433
0
    return 1;
434
0
  }
435
  // Zero- and one-element lists are always sorted.
436
0
  return sk->sorted || (sk->comp != nullptr && sk->num < 2);
437
0
}
438
439
OPENSSL_sk_cmp_func OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk,
440
0
                                            OPENSSL_sk_cmp_func comp) {
441
0
  OPENSSL_sk_cmp_func old = sk->comp;
442
443
0
  if (sk->comp != comp) {
444
0
    sk->sorted = 0;
445
0
  }
446
0
  sk->comp = comp;
447
448
0
  return old;
449
0
}
450
451
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
452
                                    OPENSSL_sk_call_copy_func call_copy_func,
453
                                    OPENSSL_sk_copy_func copy_func,
454
                                    OPENSSL_sk_call_free_func call_free_func,
455
148k
                                    OPENSSL_sk_free_func free_func) {
456
148k
  OPENSSL_STACK *ret = OPENSSL_sk_dup(sk);
457
148k
  if (ret == nullptr) {
458
0
    return nullptr;
459
0
  }
460
461
300k
  for (size_t i = 0; i < ret->num; i++) {
462
152k
    if (ret->data[i] == nullptr) {
463
328
      continue;
464
328
    }
465
152k
    ret->data[i] = call_copy_func(copy_func, ret->data[i]);
466
152k
    if (ret->data[i] == nullptr) {
467
0
      for (size_t j = 0; j < i; j++) {
468
0
        if (ret->data[j] != nullptr) {
469
0
          call_free_func(free_func, ret->data[j]);
470
0
        }
471
0
      }
472
0
      OPENSSL_sk_free(ret);
473
0
      return nullptr;
474
0
    }
475
152k
  }
476
477
148k
  return ret;
478
148k
}
479
480
0
OPENSSL_STACK *sk_new_null() { return OPENSSL_sk_new_null(); }
481
482
0
size_t sk_num(const OPENSSL_STACK *sk) { return OPENSSL_sk_num(sk); }
483
484
0
void *sk_value(const OPENSSL_STACK *sk, size_t i) {
485
0
  return OPENSSL_sk_value(sk, i);
486
0
}
487
488
0
void sk_free(OPENSSL_STACK *sk) { OPENSSL_sk_free(sk); }
489
490
0
size_t sk_push(OPENSSL_STACK *sk, void *p) { return OPENSSL_sk_push(sk, p); }
491
492
0
void *sk_pop(OPENSSL_STACK *sk) { return OPENSSL_sk_pop(sk); }
493
494
void sk_pop_free_ex(OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func,
495
0
                    OPENSSL_sk_free_func free_func) {
496
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func, free_func);
497
0
}