Coverage Report

Created: 2026-10-19 07:10

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
1.16M
OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_cmp_func comp) {
50
1.16M
  OPENSSL_STACK *ret = New<OPENSSL_STACK>();
51
1.16M
  if (ret == nullptr) {
52
0
    return nullptr;
53
0
  }
54
55
1.16M
  ret->data =
56
1.16M
      reinterpret_cast<void **>(OPENSSL_calloc(kMinSize, sizeof(void *)));
57
1.16M
  if (ret->data == nullptr) {
58
0
    goto err;
59
0
  }
60
61
1.16M
  ret->comp = comp;
62
1.16M
  ret->num_alloc = kMinSize;
63
64
1.16M
  return ret;
65
66
0
err:
67
0
  Delete(ret);
68
0
  return nullptr;
69
1.16M
}
70
71
1.16M
OPENSSL_STACK *OPENSSL_sk_new_null() { return OPENSSL_sk_new(nullptr); }
72
73
6.60M
size_t OPENSSL_sk_num(const OPENSSL_STACK *sk) {
74
6.60M
  if (sk == nullptr) {
75
230k
    return 0;
76
230k
  }
77
6.37M
  return sk->num;
78
6.60M
}
79
80
4.98k
void OPENSSL_sk_zero(OPENSSL_STACK *sk) {
81
4.98k
  if (sk == nullptr || sk->num == 0) {
82
4.98k
    return;
83
4.98k
  }
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
6.87M
void *OPENSSL_sk_value(const OPENSSL_STACK *sk, size_t i) {
90
6.87M
  if (!sk || i >= sk->num) {
91
0
    return nullptr;
92
0
  }
93
6.87M
  return sk->data[i];
94
6.87M
}
95
96
0
void *OPENSSL_sk_last(const OPENSSL_STACK *sk) {
97
0
  if (!sk || sk->num == 0) {
98
0
    return nullptr;
99
0
  }
100
0
  return sk->data[sk->num - 1];
101
0
}
102
103
116k
void *OPENSSL_sk_set(OPENSSL_STACK *sk, size_t i, void *value) {
104
116k
  if (!sk || i >= sk->num) {
105
0
    return nullptr;
106
0
  }
107
116k
  sk->sorted = 0;
108
116k
  return sk->data[i] = value;
109
116k
}
110
111
1.45M
void OPENSSL_sk_free(OPENSSL_STACK *sk) {
112
1.45M
  if (sk == nullptr) {
113
78.9k
    return;
114
78.9k
  }
115
1.37M
  OPENSSL_free(sk->data);
116
1.37M
  Delete(sk);
117
1.37M
}
118
119
void OPENSSL_sk_pop_free_ex(OPENSSL_STACK *sk,
120
                            OPENSSL_sk_call_free_func call_free_func,
121
2.39M
                            OPENSSL_sk_free_func free_func) {
122
2.39M
  if (sk == nullptr) {
123
1.22M
    return;
124
1.22M
  }
125
126
3.67M
  for (size_t i = 0; i < sk->num; i++) {
127
2.50M
    if (sk->data[i] != nullptr) {
128
2.50M
      call_free_func(free_func, sk->data[i]);
129
2.50M
    }
130
2.50M
  }
131
1.17M
  OPENSSL_sk_free(sk);
132
1.17M
}
133
134
// Historically, `sk_pop_free` called the function as `OPENSSL_sk_free_func`
135
// directly. This is undefined in C. Some callers called `sk_pop_free` directly,
136
// so we must maintain a compatibility version for now.
137
0
static void call_free_func_legacy(OPENSSL_sk_free_func func, void *ptr) {
138
0
  func(ptr);
139
0
}
140
141
0
void sk_pop_free(OPENSSL_STACK *sk, OPENSSL_sk_free_func free_func) {
142
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func_legacy, free_func);
143
0
}
144
145
2.99M
size_t OPENSSL_sk_insert(OPENSSL_STACK *sk, void *p, size_t where) {
146
2.99M
  if (sk == nullptr) {
147
0
    return 0;
148
0
  }
149
150
2.99M
  if (sk->num >= INT_MAX) {
151
0
    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
152
0
    return 0;
153
0
  }
154
155
2.99M
  if (sk->num_alloc <= sk->num + 1) {
156
    // Attempt to double the size of the array.
157
156k
    size_t new_alloc = sk->num_alloc << 1;
158
156k
    size_t alloc_size = new_alloc * sizeof(void *);
159
156k
    void **data;
160
161
    // If the doubling overflowed, try to increment.
162
156k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
163
0
      new_alloc = sk->num_alloc + 1;
164
0
      alloc_size = new_alloc * sizeof(void *);
165
0
    }
166
167
    // If the increment also overflowed, fail.
168
156k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
169
0
      return 0;
170
0
    }
171
172
156k
    data = reinterpret_cast<void **>(OPENSSL_realloc(sk->data, alloc_size));
173
156k
    if (data == nullptr) {
174
0
      return 0;
175
0
    }
176
177
156k
    sk->data = data;
178
156k
    sk->num_alloc = new_alloc;
179
156k
  }
180
181
2.99M
  if (where >= sk->num) {
182
2.99M
    sk->data[sk->num] = p;
183
2.99M
  } else {
184
0
    OPENSSL_memmove(&sk->data[where + 1], &sk->data[where],
185
0
                    sizeof(void *) * (sk->num - where));
186
0
    sk->data[where] = p;
187
0
  }
188
189
2.99M
  sk->num++;
190
2.99M
  sk->sorted = 0;
191
192
2.99M
  return sk->num;
193
2.99M
}
194
195
19.7k
void *OPENSSL_sk_delete(OPENSSL_STACK *sk, size_t where) {
196
19.7k
  void *ret;
197
198
19.7k
  if (!sk || where >= sk->num) {
199
0
    return nullptr;
200
0
  }
201
202
19.7k
  ret = sk->data[where];
203
204
19.7k
  if (where != sk->num - 1) {
205
11.3k
    OPENSSL_memmove(&sk->data[where], &sk->data[where + 1],
206
11.3k
                    sizeof(void *) * (sk->num - where - 1));
207
11.3k
  }
208
209
19.7k
  sk->num--;
210
19.7k
  return ret;
211
19.7k
}
212
213
11.3k
void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *sk, const void *p) {
214
11.3k
  if (sk == nullptr) {
215
0
    return nullptr;
216
0
  }
217
218
97.7k
  for (size_t i = 0; i < sk->num; i++) {
219
97.7k
    if (sk->data[i] == p) {
220
11.3k
      return OPENSSL_sk_delete(sk, i);
221
11.3k
    }
222
97.7k
  }
223
224
0
  return nullptr;
225
11.3k
}
226
227
void OPENSSL_sk_delete_if(OPENSSL_STACK *sk,
228
                          OPENSSL_sk_call_delete_if_func call_func,
229
0
                          OPENSSL_sk_delete_if_func func, void *data) {
230
0
  if (sk == nullptr) {
231
0
    return;
232
0
  }
233
234
0
  size_t new_num = 0;
235
0
  for (size_t i = 0; i < sk->num; i++) {
236
0
    if (!call_func(func, sk->data[i], data)) {
237
0
      sk->data[new_num] = sk->data[i];
238
0
      new_num++;
239
0
    }
240
0
  }
241
0
  sk->num = new_num;
242
0
}
243
244
int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, const void *p,
245
46.0k
                    OPENSSL_sk_call_cmp_func call_cmp_func) {
246
46.0k
  if (sk == nullptr) {
247
0
    return 0;
248
0
  }
249
250
46.0k
  if (sk->comp == nullptr) {
251
    // Use pointer equality when no comparison function has been set.
252
268k
    for (size_t i = 0; i < sk->num; i++) {
253
268k
      if (sk->data[i] == p) {
254
46.0k
        if (out_index) {
255
0
          *out_index = i;
256
0
        }
257
46.0k
        return 1;
258
46.0k
      }
259
268k
    }
260
4
    return 0;
261
46.0k
  }
262
263
0
  if (p == nullptr) {
264
0
    return 0;
265
0
  }
266
267
0
  if (!OPENSSL_sk_is_sorted(sk)) {
268
0
    for (size_t i = 0; i < sk->num; i++) {
269
0
      if (call_cmp_func(sk->comp, p, sk->data[i]) == 0) {
270
0
        if (out_index) {
271
0
          *out_index = i;
272
0
        }
273
0
        return 1;
274
0
      }
275
0
    }
276
0
    return 0;
277
0
  }
278
279
  // The stack is sorted, so binary search to find the element.
280
  //
281
  // `lo` and `hi` maintain a half-open interval of where the answer may be. All
282
  // indices such that `lo <= idx < hi` are candidates.
283
0
  size_t lo = 0, hi = sk->num;
284
0
  while (lo < hi) {
285
    // Bias `mid` towards `lo`. See the `r == 0` case below.
286
0
    size_t mid = lo + (hi - lo - 1) / 2;
287
0
    assert(lo <= mid && mid < hi);
288
0
    int r = call_cmp_func(sk->comp, p, sk->data[mid]);
289
0
    if (r > 0) {
290
0
      lo = mid + 1;  // `mid` is too low.
291
0
    } else if (r < 0) {
292
0
      hi = mid;  // `mid` is too high.
293
0
    } else {
294
      // `mid` matches. However, this function returns the earliest match, so we
295
      // can only return if the range has size one.
296
0
      if (hi - lo == 1) {
297
0
        if (out_index != nullptr) {
298
0
          *out_index = mid;
299
0
        }
300
0
        return 1;
301
0
      }
302
      // The sample is biased towards `lo`. `mid` can only be `hi - 1` if
303
      // `hi - lo` was one, so this makes forward progress.
304
0
      assert(mid + 1 < hi);
305
0
      hi = mid + 1;
306
0
    }
307
0
  }
308
309
0
  assert(lo == hi);
310
0
  return 0;  // Not found.
311
0
}
312
313
0
void *OPENSSL_sk_shift(OPENSSL_STACK *sk) {
314
0
  if (sk == nullptr) {
315
0
    return nullptr;
316
0
  }
317
0
  if (sk->num == 0) {
318
0
    return nullptr;
319
0
  }
320
0
  return OPENSSL_sk_delete(sk, 0);
321
0
}
322
323
2.96M
size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p) {
324
2.96M
  return OPENSSL_sk_insert(sk, p, sk->num);
325
2.96M
}
326
327
8.41k
void *OPENSSL_sk_pop(OPENSSL_STACK *sk) {
328
8.41k
  if (sk == nullptr) {
329
0
    return nullptr;
330
0
  }
331
8.41k
  if (sk->num == 0) {
332
0
    return nullptr;
333
0
  }
334
8.41k
  return OPENSSL_sk_delete(sk, sk->num - 1);
335
8.41k
}
336
337
206k
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk) {
338
206k
  if (sk == nullptr) {
339
0
    return nullptr;
340
0
  }
341
342
206k
  OPENSSL_STACK *ret = New<OPENSSL_STACK>();
343
206k
  if (ret == nullptr) {
344
0
    return nullptr;
345
0
  }
346
347
206k
  ret->data = reinterpret_cast<void **>(
348
206k
      OPENSSL_memdup(sk->data, sizeof(void *) * sk->num_alloc));
349
206k
  if (ret->data == nullptr) {
350
0
    goto err;
351
0
  }
352
353
206k
  ret->num = sk->num;
354
206k
  ret->sorted = sk->sorted;
355
206k
  ret->num_alloc = sk->num_alloc;
356
206k
  ret->comp = sk->comp;
357
206k
  return ret;
358
359
0
err:
360
0
  OPENSSL_sk_free(ret);
361
0
  return nullptr;
362
206k
}
363
364
void OPENSSL_sk_sort(OPENSSL_STACK *sk,
365
0
                     OPENSSL_sk_call_cmp_func call_cmp_func) {
366
0
  if (sk == nullptr || sk->comp == nullptr || sk->sorted) {
367
0
    return;
368
0
  }
369
370
0
  std::sort(sk->data, sk->data + sk->num, [&](void *a, void *b) {
371
0
    return call_cmp_func(sk->comp, a, b) < 0;
372
0
  });
373
0
  sk->sorted = 1;
374
0
}
375
376
void OPENSSL_sk_sort_and_dedup(
377
    OPENSSL_STACK *sk, OPENSSL_sk_call_cmp_func call_cmp_func,
378
0
    OPENSSL_sk_call_free_func call_free_func, OPENSSL_sk_free_func free_func) {
379
0
  OPENSSL_sk_sort(sk, call_cmp_func);
380
0
  if (sk == nullptr || sk->comp == nullptr || sk->num <= 1) {
381
0
    return;
382
0
  }
383
384
0
  size_t new_num = 1;
385
0
  for (size_t i = 1; i < sk->num; i++) {
386
0
    if (call_cmp_func(sk->comp, sk->data[i], sk->data[new_num - 1]) != 0) {
387
0
      sk->data[new_num] = sk->data[i];
388
0
      new_num++;
389
0
    } else if (free_func != nullptr) {
390
0
      call_free_func(free_func, sk->data[i]);
391
0
    }
392
0
  }
393
0
  sk->num = new_num;
394
0
}
395
396
0
int OPENSSL_sk_is_sorted(const OPENSSL_STACK *sk) {
397
0
  if (!sk) {
398
0
    return 1;
399
0
  }
400
  // Zero- and one-element lists are always sorted.
401
0
  return sk->sorted || (sk->comp != nullptr && sk->num < 2);
402
0
}
403
404
OPENSSL_sk_cmp_func OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk,
405
0
                                            OPENSSL_sk_cmp_func comp) {
406
0
  OPENSSL_sk_cmp_func old = sk->comp;
407
408
0
  if (sk->comp != comp) {
409
0
    sk->sorted = 0;
410
0
  }
411
0
  sk->comp = comp;
412
413
0
  return old;
414
0
}
415
416
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
417
                                    OPENSSL_sk_call_copy_func call_copy_func,
418
                                    OPENSSL_sk_copy_func copy_func,
419
                                    OPENSSL_sk_call_free_func call_free_func,
420
147k
                                    OPENSSL_sk_free_func free_func) {
421
147k
  OPENSSL_STACK *ret = OPENSSL_sk_dup(sk);
422
147k
  if (ret == nullptr) {
423
0
    return nullptr;
424
0
  }
425
426
301k
  for (size_t i = 0; i < ret->num; i++) {
427
153k
    if (ret->data[i] == nullptr) {
428
351
      continue;
429
351
    }
430
152k
    ret->data[i] = call_copy_func(copy_func, ret->data[i]);
431
152k
    if (ret->data[i] == nullptr) {
432
0
      for (size_t j = 0; j < i; j++) {
433
0
        if (ret->data[j] != nullptr) {
434
0
          call_free_func(free_func, ret->data[j]);
435
0
        }
436
0
      }
437
0
      OPENSSL_sk_free(ret);
438
0
      return nullptr;
439
0
    }
440
152k
  }
441
442
147k
  return ret;
443
147k
}
444
445
0
OPENSSL_STACK *sk_new_null() { return OPENSSL_sk_new_null(); }
446
447
0
size_t sk_num(const OPENSSL_STACK *sk) { return OPENSSL_sk_num(sk); }
448
449
0
void *sk_value(const OPENSSL_STACK *sk, size_t i) {
450
0
  return OPENSSL_sk_value(sk, i);
451
0
}
452
453
0
void sk_free(OPENSSL_STACK *sk) { OPENSSL_sk_free(sk); }
454
455
0
size_t sk_push(OPENSSL_STACK *sk, void *p) { return OPENSSL_sk_push(sk, p); }
456
457
0
void *sk_pop(OPENSSL_STACK *sk) { return OPENSSL_sk_pop(sk); }
458
459
void sk_pop_free_ex(OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func,
460
0
                    OPENSSL_sk_free_func free_func) {
461
0
  OPENSSL_sk_pop_free_ex(sk, call_free_func, free_func);
462
0
}