DEFINE_STACK_OF(3SSL)
π DEFINE_STACK_OF π (that's DEFINE_STACK_OF(3SSL) bestie, from OpenSSL β¨)
okay so. stack container. that's it, that's the vibe. but like, a whole family of macros and functions that all hang out together and gently hold your pointers in a very specific order. let's get into it π«Ά
β¨ NAME β¨
so this whole page is about these, and yes you do need to meet all of them, there's no skipping:
the macro girlies:
DEFINE_STACK_OFDEFINE_STACK_OF_CONSTDEFINE_SPECIAL_STACK_OFDEFINE_SPECIAL_STACK_OF_CONST
the sk_TYPE_ crew:
sk_TYPE_num,sk_TYPE_value,sk_TYPE_new,sk_TYPE_new_null,sk_TYPE_reserve,sk_TYPE_free,sk_TYPE_zero,sk_TYPE_delete,sk_TYPE_delete_ptr,sk_TYPE_push,sk_TYPE_unshift,sk_TYPE_pop,sk_TYPE_shift,sk_TYPE_pop_free,sk_TYPE_insert,sk_TYPE_set,sk_TYPE_find,sk_TYPE_find_ex,sk_TYPE_find_all,sk_TYPE_sort,sk_TYPE_is_sorted,sk_TYPE_dup,sk_TYPE_deep_copy,sk_TYPE_set_cmp_func,sk_TYPE_new_reserve
the raw OPENSSL_sk_ crew (iykyk):
OPENSSL_sk_deep_copy,OPENSSL_sk_delete,OPENSSL_sk_delete_ptr,OPENSSL_sk_dup,OPENSSL_sk_find,OPENSSL_sk_find_ex,OPENSSL_sk_find_all,OPENSSL_sk_free,OPENSSL_sk_insert,OPENSSL_sk_is_sorted,OPENSSL_sk_new,OPENSSL_sk_new_null,OPENSSL_sk_new_reserve,OPENSSL_sk_num,OPENSSL_sk_pop,OPENSSL_sk_pop_free,OPENSSL_sk_push,OPENSSL_sk_reserve,OPENSSL_sk_set,OPENSSL_sk_set_thunks,OPENSSL_sk_set_cmp_thunks,OPENSSL_sk_set_cmp_func,OPENSSL_sk_shift,OPENSSL_sk_sort,OPENSSL_sk_unshift,OPENSSL_sk_value,OPENSSL_sk_zero
and what is all that? a stack container. that's the whole point. π
π SYNOPSIS π
here's the whole shape of it, verbatim, don't touch a character:
#include <openssl/safestack.h>
STACK_OF(TYPE)
DEFINE_STACK_OF(TYPE)
DEFINE_STACK_OF_CONST(TYPE)
DEFINE_SPECIAL_STACK_OF(FUNCTYPE, TYPE)
DEFINE_SPECIAL_STACK_OF_CONST(FUNCTYPE, TYPE)
typedef int (*sk_TYPE_compfunc)(const TYPE *const *a, const TYPE *const *b);
typedef TYPE * (*sk_TYPE_copyfunc)(const TYPE *a);
typedef void (*sk_TYPE_freefunc)(TYPE *a);
int sk_TYPE_num(const STACK_OF(TYPE) *sk);
TYPE *sk_TYPE_value(const STACK_OF(TYPE) *sk, int idx);
STACK_OF(TYPE) *sk_TYPE_new(sk_TYPE_compfunc compare);
STACK_OF(TYPE) *sk_TYPE_new_null(void);
int sk_TYPE_reserve(STACK_OF(TYPE) *sk, int n);
void sk_TYPE_free(STACK_OF(TYPE) *sk);
void sk_TYPE_zero(STACK_OF(TYPE) *sk);
TYPE *sk_TYPE_delete(STACK_OF(TYPE) *sk, int i);
TYPE *sk_TYPE_delete_ptr(STACK_OF(TYPE) *sk, TYPE *ptr);
int sk_TYPE_push(STACK_OF(TYPE) *sk, const TYPE *ptr);
int sk_TYPE_unshift(STACK_OF(TYPE) *sk, const TYPE *ptr);
TYPE *sk_TYPE_pop(STACK_OF(TYPE) *sk);
TYPE *sk_TYPE_shift(STACK_OF(TYPE) *sk);
void sk_TYPE_pop_free(STACK_OF(TYPE) *sk, sk_TYPE_freefunc freefunc);
int sk_TYPE_insert(STACK_OF(TYPE) *sk, TYPE *ptr, int idx);
TYPE *sk_TYPE_set(STACK_OF(TYPE) *sk, int idx, const TYPE *ptr);
int sk_TYPE_find(const STACK_OF(TYPE) *sk, TYPE *ptr);
int sk_TYPE_find_ex(const STACK_OF(TYPE) *sk, TYPE *ptr);
int sk_TYPE_find_all(const STACK_OF(TYPE) *sk, TYPE *ptr, int *pnum);
void sk_TYPE_sort(const STACK_OF(TYPE) *sk);
int sk_TYPE_is_sorted(const STACK_OF(TYPE) *sk);
STACK_OF(TYPE) *sk_TYPE_dup(const STACK_OF(TYPE) *sk);
STACK_OF(TYPE) *sk_TYPE_deep_copy(const STACK_OF(TYPE) *sk,
sk_TYPE_copyfunc copyfunc,
sk_TYPE_freefunc freefunc);
sk_TYPE_compfunc (*sk_TYPE_set_cmp_func(STACK_OF(TYPE) *sk,
sk_TYPE_compfunc compare));
STACK_OF(TYPE) *sk_TYPE_new_reserve(sk_TYPE_compfunc compare, int n);
πΈ DESCRIPTION πΈ
ok so here's the whole concept, and honestly it's kind of slay:
apps can build and use their own stacks by dropping any of the macros below into a header file. those macros define typesafe inline functions that wrap around the utility OPENSSL_sk_ API. and throughout this whole page, TYPE is just a placeholder β it stands in for any of the OpenSSL datatypes, like X509.
STACK_OF() hands you back the name for a stack of the specified TYPE. it's an opaque pointer to a structure declaration, and you can use it in every header file that references the stack. then there's a whole bunch of DEFINE... macros that create static inline functions for all the functions described on this page. those normally get used in one source file, and the stack manipulation gets wrapped up in application-specific functions. cozy.
DEFINE_STACK_OF() creates the set of functions for a stack of TYPE elements. the type is referenced by STACK_OF(TYPE) and every function name starts with sk_TYPE_. and DEFINE_STACK_OF_CONST() is literally identical to DEFINE_STACK_OF() except each element is constant. same energy, one tiny lil difference:
/* DEFINE_STACK_OF(TYPE) */
TYPE *sk_TYPE_value(STACK_OF(TYPE) *sk, int idx);
/* DEFINE_STACK_OF_CONST(TYPE) */
const TYPE *sk_TYPE_value(STACK_OF(TYPE) *sk, int idx);
DEFINE_SPECIAL_STACK_OF() and DEFINE_SPECIAL_STACK_OF_CONST() are basically the same thing, except FUNCNAME is what gets used in the function names instead:
/* DEFINE_SPECIAL_STACK_OF(TYPE, FUNCNAME) */
TYPE *sk_FUNCNAME_value(STACK_OF(TYPE) *sk, int idx);
/* DEFINE_SPECIAL_STACK_OF(TYPE, FUNCNAME) */
const TYPE *sk_FUNCNAME_value(STACK_OF(TYPE) *sk, int idx);
now, function by function, bestie, because every single one matters:
sk_TYPE_num()β returns the number of elements insk, or-1ifskis NULL. (rude of it, but okay.)sk_TYPE_value()β returns elementidxinsk, andidxstarts at zero, like a normal person's index. ifidxis out of range, you get NULL back.sk_TYPE_new()β allocates a brand new empty stack, using comparison functioncompare. ifcompareis NULL, then no comparison function is used at all. this one is equivalent tosk_TYPE_new_reserve(compare, 0).sk_TYPE_new_null()β allocates a new empty stack with no comparison function. equivalent tosk_TYPE_new_reserve(NULL, 0).sk_TYPE_reserve()β allocates extra memory inside theskstructure so that the nextncalls tosk_TYPE_insert(),sk_TYPE_push()orsk_TYPE_unshift()will not fail and won't cause memory to be allocated or reallocated. ifnis zero, any excess space allocated in theskstructure gets freed. and on error,skis unchanged. π«Άsk_TYPE_new_reserve()β allocates a new stack. the new stack will have additional memory allocated to holdnelements ifnis positive. then those nextncalls tosk_TYPE_insert(),sk_TYPE_push()orsk_TYPE_unshift()will not fail or cause memory to be allocated or reallocated. ifnis zero or less than zero, no memory is allocated. it also sets the comparison functioncompareon the newly created stack. ifcompareis NULL then no comparison function is used.sk_TYPE_set_cmp_func()β sets the comparison function ofsktocompare. the previous comparison function gets returned, or NULL if there was no previous comparison function.sk_TYPE_free()β frees up theskstructure. it does not free up any elements ofskβ just the container itself. after this call,skis no longer valid. πsk_TYPE_zero()β sets the number of elements inskto zero. it does not freesk, so after this callskis still valid. she survives. β¨sk_TYPE_pop_free()β frees up all elements ofskandskitself. the free functionfreefunc()gets called on each element to free it.sk_TYPE_delete()β deletes elementifromsk. returns the deleted element, or NULL ifiis out of range.sk_TYPE_delete_ptr()β deletes the element matchingptrfromsk. returns the deleted element, or NULL if no element matchingptrwas found.sk_TYPE_insert()β insertsptrintoskat positionidx. any existing elements at or afteridxget moved downwards (they're so chill about it). ifidxis out of range, the new element is just appended tosk. it returns the number of elements inskafter the new element is inserted, or zero if an error (like a memory allocation failure) happened.sk_TYPE_push()β appendsptrtosk. it's equivalent to:
sk_TYPE_insert(sk, ptr, -1);
sk_TYPE_unshift()β insertsptrat the start ofsk. it's equivalent to:
sk_TYPE_insert(sk, ptr, 0);
sk_TYPE_pop()β returns and removes the last element fromsk.sk_TYPE_shift()β returns and removes the first element fromsk.sk_TYPE_set()β sets elementidxofsktoptr, replacing the current element. the new element value is returned, or NULL if an error occurred β and that error will only happen ifskis NULL oridxis out of range.sk_TYPE_find()β searchesskfor the elementptr. when no comparison function has been specified, it does a linear search for a pointer equal toptr. when a comparison function has been specified, it searches for an element that the comparison function says is a match. if the stack is sorted, a binary search is used; otherwise, a linear search is used. it returns the index of a matching element, or-1if there is no match.sk_TYPE_find_ex()β operates likesk_TYPE_find()except when a comparison function has been specified and no matching element is found. instead of returning-1,sk_TYPE_find_ex()returns the index of the element either before or after the location whereptrwould be if it were present insk. also, it does not guarantee that the first matching element in the sorted stack is the one returned. sneaky, but noted. πsk_TYPE_find_all()β operates likesk_TYPE_find()but it also sets*pnumto the number of matching elements in the stack. in the case where no comparison function has been specified,*pnumwill always be set to1if a matching element was found, and0otherwise.sk_TYPE_sort()β sortsskusing the supplied comparison function.sk_TYPE_is_sorted()β returns1ifskis sorted and0otherwise.sk_TYPE_dup()β returns a shallow copy ofsk, or an empty stack if the passed stack is NULL. heads up though: the pointers in the copy are identical to the original. same pointers, new container. πsk_TYPE_deep_copy()β returns a new stack where each element has been copied, or an empty stack if the passed stack is NULL. the copying is performed by the suppliedcopyfunc()and the freeing byfreefunc(). andfreefunc()is only called if an error occurs. noted, bestie.
π NOTES π
ok so bestie, listen up, because these notes are lowkey the most important part π
- β οΈ Be careful with stacks in multi-threaded environments, fr fr. Anything that makes a stack bigger β like
sk_TYPE_insert()orsk_TYPE_push()β can "grow" the size of an internal array, and that causes race conditions if the same stack gets touched in a different thread. And heads up,sk_TYPE_find()andsk_TYPE_sort()can also reorder the stack. π - π§ Any comparison function you hand over should use a metric that actually works for a binary search, okay? Meaning: it returns zero, a positive value, or a negative value depending on whether a is equal to, greater than, or less than b respectively. That's the whole vibe check. β¨
- π¨ Okay this one catches people constantly: be careful checking return values from
sk_TYPE_find()andsk_TYPE_find_ex(). They return an index to the matching element β and0means it matched the first element, not "no match." A failed search is indicated by a-1return value. So index0= slay,-1= not found. Don't get it twisted. π - π
STACK_OF(),DEFINE_STACK_OF(),DEFINE_STACK_OF_CONST(), andDEFINE_SPECIAL_STACK_OF()are implemented as macros. - π«Ά It is not an error to call
sk_TYPE_num(),sk_TYPE_value(),sk_TYPE_free(),sk_TYPE_zero(),sk_TYPE_pop_free(),sk_TYPE_delete(),sk_TYPE_delete_ptr(),sk_TYPE_pop(),sk_TYPE_shift(),sk_TYPE_find(),sk_TYPE_find_ex(), andsk_TYPE_find_all()on aNULLstack, an empty stack, or with an invalid index. No error is raised under these conditions. It's giving "chill, we're fine." π - π
ββοΈ The underlying utility
OPENSSL_sk_API should not be used directly. It defines these functions:OPENSSL_sk_deep_copy(),OPENSSL_sk_delete(),OPENSSL_sk_delete_ptr(),OPENSSL_sk_dup(),OPENSSL_sk_find(),OPENSSL_sk_find_ex(),OPENSSL_sk_find_all(),OPENSSL_sk_free(),OPENSSL_sk_insert(),OPENSSL_sk_is_sorted(),OPENSSL_sk_new(),OPENSSL_sk_new_null(),OPENSSL_sk_new_reserve(),OPENSSL_sk_num(),OPENSSL_sk_pop(),OPENSSL_sk_pop_free(),OPENSSL_sk_push(),OPENSSL_sk_reserve(),OPENSSL_sk_set(),OPENSSL_sk_set_cmp_func(),OPENSSL_sk_set_thunks(),OPENSSL_sk_set_cmp_thunks(),OPENSSL_sk_shift(),OPENSSL_sk_sort(),OPENSSL_sk_unshift(),OPENSSL_sk_value(),OPENSSL_sk_zero(). - π
OPENSSL_sk_set_thunks()andOPENSSL_sk_set_cmp_thunks(), while public by necessity, are actually internal and should not be used. Not me warning you twice. Don't touch. π«
π RETURN VALUES π
okay here's the whole receipts list, bestie, no skipping π§Ύβ¨
sk_TYPE_num()β returns the number of elements in the stack, or-1if the passed stack isNULL.sk_TYPE_value()β returns a pointer to a stack element, orNULLif the index is out of range.sk_TYPE_new(),sk_TYPE_new_null()andsk_TYPE_new_reserve()β return an empty stack, orNULLif an error occurs.sk_TYPE_reserve()β returns1on successful allocation of the required memory, or0on error.sk_TYPE_set_cmp_func()β returns the old comparison function, orNULLif there was no old comparison function.sk_TYPE_free(),sk_TYPE_zero(),sk_TYPE_pop_free()andsk_TYPE_sort()β do not return values. they simply vibe. πΈsk_TYPE_pop(),sk_TYPE_shift(),sk_TYPE_delete()andsk_TYPE_delete_ptr()β return a pointer to the deleted element, orNULLon error.sk_TYPE_insert(),sk_TYPE_push()andsk_TYPE_unshift()β return the total number of elements in the stack, and0if an error occurred.sk_TYPE_set()β returns a pointer to the replacement element, orNULLon error.sk_TYPE_find()andsk_TYPE_find_ex()β return an index to the found element, or-1on error.sk_TYPE_is_sorted()β returns1if the stack is sorted and0if it is not.sk_TYPE_dup()andsk_TYPE_deep_copy()β return a pointer to the copy of the stack, orNULLon error.
π HISTORY π
storytime, because this API has lore π§β¨
- Before OpenSSL 1.1.0, this was implemented via macros and not inline functions, and it was not a public API.
sk_TYPE_reserve()andsk_TYPE_new_reserve()were added in OpenSSL 1.1.1.- From OpenSSL 3.2.0, the
sk_TYPE_find(),sk_TYPE_find_ex()andsk_TYPE_find_all()calls are read-only and do not sort the stack. To avoid any performance implications this change introduces,sk_TYPE_sort()should be called before these find operations. π - Before OpenSSL 3.3.0,
sk_TYPE_push()returned-1ifskwasNULL. It was changed to return0in this condition, as for other errors. OPENSSL_sk_set_thunks()was added in OpenSSL 3.6.0.OPENSSL_sk_set_cmp_thunks()was added in OpenSSL 4.0.0
β COPYRIGHT β
Copyright 2000-2026 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.
and that's a wrap on DEFINE_STACK_OF(3SSL), bestie β this one's from version 4.0.3, dated 2026-09-29 π«Ά go forth and stack responsibly, mwah π
π
π¦ where this page comes from
- ubuntu stonking: libssl-doc 4.0.3-1ubuntu1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms