stack.c
Go to the documentation of this file.
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to. The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  * notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  * notice, this list of conditions and the following disclaimer in the
29  * documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  * must display the following acknowledgement:
32  * "This product includes cryptographic software written by
33  * Eric Young (eay@cryptsoft.com)"
34  * The word 'cryptographic' can be left out if the rouines from the library
35  * being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  * the apps directory (application code) you must include an acknowledgement:
38  * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed. i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/stack.h>
58 
59 #include <assert.h>
60 
61 #include <openssl/mem.h>
62 
63 #include "../internal.h"
64 
65 
66 // kMinSize is the number of pointers that will be initially allocated in a new
67 // stack.
68 static const size_t kMinSize = 4;
69 
71  _STACK *ret = OPENSSL_malloc(sizeof(_STACK));
72  if (ret == NULL) {
73  return NULL;
74  }
75  OPENSSL_memset(ret, 0, sizeof(_STACK));
76 
77  ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize);
78  if (ret->data == NULL) {
79  goto err;
80  }
81 
82  OPENSSL_memset(ret->data, 0, sizeof(void *) * kMinSize);
83 
84  ret->comp = comp;
85  ret->num_alloc = kMinSize;
86 
87  return ret;
88 
89 err:
91  return NULL;
92 }
93 
94 _STACK *sk_new_null(void) { return sk_new(NULL); }
95 
96 size_t sk_num(const _STACK *sk) {
97  if (sk == NULL) {
98  return 0;
99  }
100  return sk->num;
101 }
102 
103 void sk_zero(_STACK *sk) {
104  if (sk == NULL || sk->num == 0) {
105  return;
106  }
107  OPENSSL_memset(sk->data, 0, sizeof(void*) * sk->num);
108  sk->num = 0;
109  sk->sorted = 0;
110 }
111 
112 void *sk_value(const _STACK *sk, size_t i) {
113  if (!sk || i >= sk->num) {
114  return NULL;
115  }
116  return sk->data[i];
117 }
118 
119 void *sk_set(_STACK *sk, size_t i, void *value) {
120  if (!sk || i >= sk->num) {
121  return NULL;
122  }
123  return sk->data[i] = value;
124 }
125 
126 void sk_free(_STACK *sk) {
127  if (sk == NULL) {
128  return;
129  }
130  OPENSSL_free(sk->data);
131  OPENSSL_free(sk);
132 }
133 
134 void sk_pop_free_ex(_STACK *sk, void (*call_free_func)(stack_free_func, void *),
135  stack_free_func free_func) {
136  if (sk == NULL) {
137  return;
138  }
139 
140  for (size_t i = 0; i < sk->num; i++) {
141  if (sk->data[i] != NULL) {
142  call_free_func(free_func, sk->data[i]);
143  }
144  }
145  sk_free(sk);
146 }
147 
148 // Historically, |sk_pop_free| called the function as |stack_free_func|
149 // directly. This is undefined in C. Some callers called |sk_pop_free| directly,
150 // so we must maintain a compatibility version for now.
152  func(ptr);
153 }
154 
155 void sk_pop_free(_STACK *sk, stack_free_func free_func) {
156  sk_pop_free_ex(sk, call_free_func_legacy, free_func);
157 }
158 
159 size_t sk_insert(_STACK *sk, void *p, size_t where) {
160  if (sk == NULL) {
161  return 0;
162  }
163 
164  if (sk->num_alloc <= sk->num + 1) {
165  // Attempt to double the size of the array.
166  size_t new_alloc = sk->num_alloc << 1;
167  size_t alloc_size = new_alloc * sizeof(void *);
168  void **data;
169 
170  // If the doubling overflowed, try to increment.
171  if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
172  new_alloc = sk->num_alloc + 1;
173  alloc_size = new_alloc * sizeof(void *);
174  }
175 
176  // If the increment also overflowed, fail.
177  if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
178  return 0;
179  }
180 
181  data = OPENSSL_realloc(sk->data, alloc_size);
182  if (data == NULL) {
183  return 0;
184  }
185 
186  sk->data = data;
187  sk->num_alloc = new_alloc;
188  }
189 
190  if (where >= sk->num) {
191  sk->data[sk->num] = p;
192  } else {
193  OPENSSL_memmove(&sk->data[where + 1], &sk->data[where],
194  sizeof(void *) * (sk->num - where));
195  sk->data[where] = p;
196  }
197 
198  sk->num++;
199  sk->sorted = 0;
200 
201  return sk->num;
202 }
203 
204 void *sk_delete(_STACK *sk, size_t where) {
205  void *ret;
206 
207  if (!sk || where >= sk->num) {
208  return NULL;
209  }
210 
211  ret = sk->data[where];
212 
213  if (where != sk->num - 1) {
214  OPENSSL_memmove(&sk->data[where], &sk->data[where + 1],
215  sizeof(void *) * (sk->num - where - 1));
216  }
217 
218  sk->num--;
219  return ret;
220 }
221 
222 void *sk_delete_ptr(_STACK *sk, const void *p) {
223  if (sk == NULL) {
224  return NULL;
225  }
226 
227  for (size_t i = 0; i < sk->num; i++) {
228  if (sk->data[i] == p) {
229  return sk_delete(sk, i);
230  }
231  }
232 
233  return NULL;
234 }
235 
236 int sk_find(const _STACK *sk, size_t *out_index, const void *p,
237  int (*call_cmp_func)(stack_cmp_func, const void **,
238  const void **)) {
239  if (sk == NULL) {
240  return 0;
241  }
242 
243  if (sk->comp == NULL) {
244  // Use pointer equality when no comparison function has been set.
245  for (size_t i = 0; i < sk->num; i++) {
246  if (sk->data[i] == p) {
247  if (out_index) {
248  *out_index = i;
249  }
250  return 1;
251  }
252  }
253  return 0;
254  }
255 
256  if (p == NULL) {
257  return 0;
258  }
259 
260  if (!sk_is_sorted(sk)) {
261  for (size_t i = 0; i < sk->num; i++) {
262  const void *elem = sk->data[i];
263  if (call_cmp_func(sk->comp, &p, &elem) == 0) {
264  if (out_index) {
265  *out_index = i;
266  }
267  return 1;
268  }
269  }
270  return 0;
271  }
272 
273  // The stack is sorted, so binary search to find the element.
274  //
275  // |lo| and |hi| maintain a half-open interval of where the answer may be. All
276  // indices such that |lo <= idx < hi| are candidates.
277  size_t lo = 0, hi = sk->num;
278  while (lo < hi) {
279  // Bias |mid| towards |lo|. See the |r == 0| case below.
280  size_t mid = lo + (hi - lo - 1) / 2;
281  assert(lo <= mid && mid < hi);
282  const void *elem = sk->data[mid];
283  int r = call_cmp_func(sk->comp, &p, &elem);
284  if (r > 0) {
285  lo = mid + 1; // |mid| is too low.
286  } else if (r < 0) {
287  hi = mid; // |mid| is too high.
288  } else {
289  // |mid| matches. However, this function returns the earliest match, so we
290  // can only return if the range has size one.
291  if (hi - lo == 1) {
292  if (out_index != NULL) {
293  *out_index = mid;
294  }
295  return 1;
296  }
297  // The sample is biased towards |lo|. |mid| can only be |hi - 1| if
298  // |hi - lo| was one, so this makes forward progress.
299  assert(mid + 1 < hi);
300  hi = mid + 1;
301  }
302  }
303 
304  assert(lo == hi);
305  return 0; // Not found.
306 }
307 
308 void *sk_shift(_STACK *sk) {
309  if (sk == NULL) {
310  return NULL;
311  }
312  if (sk->num == 0) {
313  return NULL;
314  }
315  return sk_delete(sk, 0);
316 }
317 
318 size_t sk_push(_STACK *sk, void *p) { return (sk_insert(sk, p, sk->num)); }
319 
320 void *sk_pop(_STACK *sk) {
321  if (sk == NULL) {
322  return NULL;
323  }
324  if (sk->num == 0) {
325  return NULL;
326  }
327  return sk_delete(sk, sk->num - 1);
328 }
329 
330 _STACK *sk_dup(const _STACK *sk) {
331  if (sk == NULL) {
332  return NULL;
333  }
334 
335  _STACK *ret = OPENSSL_malloc(sizeof(_STACK));
336  if (ret == NULL) {
337  return NULL;
338  }
339  OPENSSL_memset(ret, 0, sizeof(_STACK));
340 
341  ret->data = OPENSSL_malloc(sizeof(void *) * sk->num_alloc);
342  if (ret->data == NULL) {
343  goto err;
344  }
345 
346  ret->num = sk->num;
347  OPENSSL_memcpy(ret->data, sk->data, sizeof(void *) * sk->num);
348  ret->sorted = sk->sorted;
349  ret->num_alloc = sk->num_alloc;
350  ret->comp = sk->comp;
351  return ret;
352 
353 err:
354  sk_free(ret);
355  return NULL;
356 }
357 
358 void sk_sort(_STACK *sk) {
359  if (sk == NULL || sk->comp == NULL || sk->sorted) {
360  return;
361  }
362 
363  // sk->comp is a function that takes pointers to pointers to elements, but
364  // qsort take a comparison function that just takes pointers to elements.
365  // However, since we're passing an array of pointers to qsort, we can just
366  // cast the comparison function and everything works.
367  //
368  // TODO(davidben): This is undefined behavior, but the call is in libc so,
369  // e.g., CFI does not notice. Unfortunately, |qsort| is missing a void*
370  // parameter in its callback and |qsort_s| / |qsort_r| are a mess of
371  // incompatibility.
372  if (sk->num >= 2) {
373  int (*comp_func)(const void *, const void *) =
374  (int (*)(const void *, const void *))(sk->comp);
375  qsort(sk->data, sk->num, sizeof(void *), comp_func);
376  }
377  sk->sorted = 1;
378 }
379 
380 int sk_is_sorted(const _STACK *sk) {
381  if (!sk) {
382  return 1;
383  }
384  return sk->sorted;
385 }
386 
388  stack_cmp_func old = sk->comp;
389 
390  if (sk->comp != comp) {
391  sk->sorted = 0;
392  }
393  sk->comp = comp;
394 
395  return old;
396 }
397 
399  void *(*call_copy_func)(stack_copy_func, void *),
400  stack_copy_func copy_func,
401  void (*call_free_func)(stack_free_func, void *),
402  stack_free_func free_func) {
403  _STACK *ret = sk_dup(sk);
404  if (ret == NULL) {
405  return NULL;
406  }
407 
408  for (size_t i = 0; i < ret->num; i++) {
409  if (ret->data[i] == NULL) {
410  continue;
411  }
412  ret->data[i] = call_copy_func(copy_func, ret->data[i]);
413  if (ret->data[i] == NULL) {
414  for (size_t j = 0; j < i; j++) {
415  if (ret->data[j] != NULL) {
416  call_free_func(free_func, ret->data[j]);
417  }
418  }
419  sk_free(ret);
420  return NULL;
421  }
422  }
423 
424  return ret;
425 }
sk_is_sorted
int sk_is_sorted(const _STACK *sk)
Definition: stack.c:380
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
kMinSize
static const size_t kMinSize
Definition: stack.c:68
stack_st::sorted
int sorted
Definition: stack.h:116
sk_set
void * sk_set(_STACK *sk, size_t i, void *value)
Definition: stack.c:119
stack_st::num_alloc
size_t num_alloc
Definition: stack.h:119
stack_st::data
void ** data
Definition: stack.h:113
stack_cmp_func
int(* stack_cmp_func)(const void **a, const void **b)
Definition: stack.h:106
sk_delete
void * sk_delete(_STACK *sk, size_t where)
Definition: stack.c:204
OPENSSL_realloc
#define OPENSSL_realloc
Definition: boringssl_prefix_symbols.h:1889
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
error_ref_leak.err
err
Definition: error_ref_leak.py:35
sk_dup
_STACK * sk_dup(const _STACK *sk)
Definition: stack.c:330
xds_manager.p
p
Definition: xds_manager.py:60
sk_pop
void * sk_pop(_STACK *sk)
Definition: stack.c:320
sk_set_cmp_func
stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp)
Definition: stack.c:387
OPENSSL_memset
static void * OPENSSL_memset(void *dst, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:835
sk_shift
void * sk_shift(_STACK *sk)
Definition: stack.c:308
OPENSSL_malloc
#define OPENSSL_malloc
Definition: boringssl_prefix_symbols.h:1885
sk_find
int sk_find(const _STACK *sk, size_t *out_index, const void *p, int(*call_cmp_func)(stack_cmp_func, const void **, const void **))
Definition: stack.c:236
sk_delete_ptr
void * sk_delete_ptr(_STACK *sk, const void *p)
Definition: stack.c:222
stack_st::num
size_t num
Definition: stack.h:112
xds_interop_client.int
int
Definition: xds_interop_client.py:113
stack_st::comp
stack_cmp_func comp
Definition: stack.h:121
sk_pop_free
void sk_pop_free(_STACK *sk, stack_free_func free_func)
Definition: stack.c:155
sk_value
void * sk_value(const _STACK *sk, size_t i)
Definition: stack.c:112
sk_free
void sk_free(_STACK *sk)
Definition: stack.c:126
OPENSSL_memcpy
static void * OPENSSL_memcpy(void *dst, const void *src, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:819
sk_new_null
_STACK * sk_new_null(void)
Definition: stack.c:94
stack_st
Definition: stack.h:110
sk_insert
size_t sk_insert(_STACK *sk, void *p, size_t where)
Definition: stack.c:159
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
qsort
void qsort(void *a, size_t n, size_t es, int(*cmp)(const void *, const void *))
Definition: qsort.h:130
stack_free_func
void(* stack_free_func)(void *ptr)
Definition: stack.h:92
sk_new
_STACK * sk_new(stack_cmp_func comp)
Definition: stack.c:70
stack_copy_func
void *(* stack_copy_func)(void *ptr)
Definition: stack.h:97
value
const char * value
Definition: hpack_parser_table.cc:165
call_free_func_legacy
static void call_free_func_legacy(stack_free_func func, void *ptr)
Definition: stack.c:151
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
sk_zero
void sk_zero(_STACK *sk)
Definition: stack.c:103
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
fix_build_deps.r
r
Definition: fix_build_deps.py:491
sk_num
size_t sk_num(const _STACK *sk)
Definition: stack.c:96
sk_pop_free_ex
void sk_pop_free_ex(_STACK *sk, void(*call_free_func)(stack_free_func, void *), stack_free_func free_func)
Definition: stack.c:134
OPENSSL_memmove
static void * OPENSSL_memmove(void *dst, const void *src, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:827
sk_push
size_t sk_push(_STACK *sk, void *p)
Definition: stack.c:318
mem.h
sk_deep_copy
_STACK * sk_deep_copy(const _STACK *sk, void *(*call_copy_func)(stack_copy_func, void *), stack_copy_func copy_func, void(*call_free_func)(stack_free_func, void *), stack_free_func free_func)
Definition: stack.c:398
OPENSSL_free
#define OPENSSL_free
Definition: boringssl_prefix_symbols.h:1869
binary_size.old
string old
Definition: binary_size.py:128
sk_sort
void sk_sort(_STACK *sk)
Definition: stack.c:358
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
stack.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:21