OPENSSL_sk_compfunc comp;
int (*cmp_thunk)(OPENSSL_sk_compfunc, const void *, const void *);
OPENSSL_sk_freefunc_thunk free_thunk;
+ OPENSSL_sk_copyfunc_thunk copy_thunk;
};
OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk,
for (i = 0; i < ret->num; ++i) {
if (sk->data[i] == NULL)
continue;
- if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {
+ if (ret->copy_thunk != NULL)
+ ret->data[i] = ret->copy_thunk(copy_func, sk->data[i]);
+ else
+ ret->data[i] = copy_func(sk->data[i]);
+
+ if (ret->data[i] == NULL) {
while (--i >= 0)
free_with_thunk(ret, free_func, ret->data[i]);
goto err;
return st;
}
+OPENSSL_STACK *OPENSSL_sk_set_copy_thunks(OPENSSL_STACK *st, OPENSSL_sk_copyfunc_thunk cp_thunk)
+{
+ if (st != NULL)
+ st->copy_thunk = cp_thunk;
+
+ return st;
+}
+
int OPENSSL_sk_insert(OPENSSL_STACK *st, const void *data, int loc)
{
int cmp_ret;
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_set_thunks, OPENSSL_sk_set_cmp_thunks, OPENSSL_sk_set_copy_thunks,
+OPENSSL_sk_set_cmp_func, OPENSSL_sk_shift,
OPENSSL_sk_sort, OPENSSL_sk_unshift, OPENSSL_sk_value, OPENSSL_sk_zero
- stack container
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_set_thunks(), OPENSSL_sk_set_cmp_thunks(),
+OPENSSL_sk_set_copy_thunks(), OPENSSL_sk_shift(), OPENSSL_sk_sort(),
OPENSSL_sk_unshift(), OPENSSL_sk_value(), OPENSSL_sk_zero().
-OPENSSL_sk_set_thunks() and OPENSSL_sk_set_cmp_thunks(), while public by necessity, are actually
-internal and should not be used.
+OPENSSL_sk_set_thunks(), OPENSSL_sk_set_cmp_thunks(), and
+OPENSSL_sk_set_copy_thunks(), while public by necessity, are actually internal
+and should not be used.
=head1 RETURN VALUES
OPENSSL_sk_set_thunks() was added in OpenSSL 3.6.0.
-OPENSSL_sk_set_cmp_thunks() was added in OpenSSL 4.0.0
+OPENSSL_sk_set_cmp_thunks() was added in OpenSSL 4.0.0.
+
+OPENSSL_sk_set_copy_thunks() was added in OpenSSL 4.1.0.
=head1 COPYRIGHT
sk_##t1##_freefunc freefunc = (sk_##t1##_freefunc)freefunc_arg; \
freefunc((t3 *)ptr); \
} \
+ static ossl_inline void *sk_##t1##_copyfunc_thunk(OPENSSL_sk_copyfunc copyfunc_arg, const void *ptr) \
+ { \
+ sk_##t1##_copyfunc copyfunc = (sk_##t1##_copyfunc)copyfunc_arg; \
+ return (void *)copyfunc((const t3 *)ptr); \
+ } \
static ossl_inline int sk_##t1##_cmpfunc_thunk(int (*cmp)(const void *, const void *), const void *a, const void *b) \
{ \
int (*realcmp)(const t3 *const *a, const t3 *const *b) = (int (*)(const t3 *const *a, const t3 *const *b))(cmp); \
sk_##t1##_freefunc freefunc = (sk_##t1##_freefunc)freefunc_arg; \
freefunc((t3 *)ptr); \
} \
+ static ossl_inline void *sk_##t1##_copyfunc_thunk(OPENSSL_sk_copyfunc copyfunc_arg, const void *ptr) \
+ { \
+ sk_##t1##_copyfunc copyfunc = (sk_##t1##_copyfunc)copyfunc_arg; \
+ return (void *)copyfunc((const t3 *)ptr); \
+ } \
static ossl_inline int sk_##t1##_cmpfunc_thunk(int (*cmp)(const void *, const void *), const void *a, const void *b) \
{ \
int (*realcmp)(const t3 *const *a, const t3 *const *b) = (int (*)(const t3 *const *a, const t3 *const *b))(cmp); \
\
f_thunk = (OPENSSL_sk_freefunc_thunk)sk_##t1##_freefunc_thunk; \
OPENSSL_sk_set_cmp_thunks(ret, sk_##t1##_cmpfunc_thunk); \
+ OPENSSL_sk_set_copy_thunks(ret, sk_##t1##_copyfunc_thunk); \
return (STACK_OF(t1) *)OPENSSL_sk_set_thunks(ret, f_thunk); \
} \
static ossl_unused ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \
\
f_thunk = (OPENSSL_sk_freefunc_thunk)sk_##t1##_freefunc_thunk; \
OPENSSL_sk_set_cmp_thunks(ret, sk_##t1##_cmpfunc_thunk); \
+ OPENSSL_sk_set_copy_thunks(ret, sk_##t1##_copyfunc_thunk); \
return (STACK_OF(t1) *)OPENSSL_sk_set_thunks(ret, f_thunk); \
} \
static ossl_unused ossl_inline STACK_OF(t1) *sk_##t1##_new_reserve(sk_##t1##_compfunc compare, int n) \
\
f_thunk = (OPENSSL_sk_freefunc_thunk)sk_##t1##_freefunc_thunk; \
OPENSSL_sk_set_cmp_thunks(ret, sk_##t1##_cmpfunc_thunk); \
+ OPENSSL_sk_set_copy_thunks(ret, sk_##t1##_copyfunc_thunk); \
return (STACK_OF(t1) *)OPENSSL_sk_set_thunks(ret, f_thunk); \
} \
static ossl_unused ossl_inline int sk_##t1##_reserve(STACK_OF(t1) *sk, int n) \
typedef void (*OPENSSL_sk_freefunc)(void *);
typedef void (*OPENSSL_sk_freefunc_thunk)(OPENSSL_sk_freefunc, void *);
typedef void *(*OPENSSL_sk_copyfunc)(const void *);
+typedef void *(*OPENSSL_sk_copyfunc_thunk)(OPENSSL_sk_copyfunc, const void *);
int OPENSSL_sk_num(const OPENSSL_STACK *);
void *OPENSSL_sk_value(const OPENSSL_STACK *, int);
OPENSSL_STACK *OPENSSL_sk_new_reserve(OPENSSL_sk_compfunc c, int n);
OPENSSL_STACK *OPENSSL_sk_set_thunks(OPENSSL_STACK *st, OPENSSL_sk_freefunc_thunk f_thunk);
OPENSSL_STACK *OPENSSL_sk_set_cmp_thunks(OPENSSL_STACK *st, int (*c_thunk)(int (*)(const void *, const void *), const void *, const void *));
+OPENSSL_STACK *OPENSSL_sk_set_copy_thunks(OPENSSL_STACK *st, OPENSSL_sk_copyfunc_thunk cp_thunk);
int OPENSSL_sk_reserve(OPENSSL_STACK *st, int n);
void OPENSSL_sk_free(OPENSSL_STACK *);
void OPENSSL_sk_pop_free(OPENSSL_STACK *st, OPENSSL_sk_freefunc func);
/*
- * Copyright 2017-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017-2026 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
OPENSSL_free(p);
}
+static char *string_copy(const char *p)
+{
+ return OPENSSL_strdup(p);
+}
+
+static void string_free(char *p)
+{
+ OPENSSL_free(p);
+}
+
static int test_SS_stack(void)
{
STACK_OF(SS) *s = sk_SS_new_null();
return testresult;
}
+static int test_OPENSSL_STRING_deep_copy_mfail(void)
+{
+ STACK_OF(OPENSSL_STRING) *s = sk_OPENSSL_STRING_new_null();
+ STACK_OF(OPENSSL_STRING) *r = NULL;
+ static const char *strings[] = {
+ "alpha", "beta", "gamma"
+ };
+ char *p;
+ int i;
+ int testresult = 0;
+
+ if (!TEST_ptr(s))
+ goto end;
+
+ for (i = 0; i < (int)OSSL_NELEM(strings); i++) {
+ p = OPENSSL_strdup(strings[i]);
+ if (!TEST_ptr(p)
+ || !TEST_int_eq(sk_OPENSSL_STRING_push(s, p), i + 1)) {
+ OPENSSL_free(p);
+ goto end;
+ }
+ }
+
+ MFAIL_start();
+ r = sk_OPENSSL_STRING_deep_copy(s, string_copy, string_free);
+ MFAIL_end();
+
+ if (r == NULL)
+ goto end;
+
+ if (!TEST_int_eq(sk_OPENSSL_STRING_num(r), sk_OPENSSL_STRING_num(s)))
+ goto end;
+
+ for (i = 0; i < sk_OPENSSL_STRING_num(s); i++) {
+ char *src = sk_OPENSSL_STRING_value(s, i);
+ char *dst = sk_OPENSSL_STRING_value(r, i);
+
+ if (!TEST_ptr_ne(dst, src)
+ || !TEST_str_eq(dst, src))
+ goto end;
+ }
+
+ testresult = 1;
+end:
+ sk_OPENSSL_STRING_pop_free(r, string_free);
+ sk_OPENSSL_STRING_pop_free(s, string_free);
+ return testresult;
+}
+
static int test_SU_stack(void)
{
STACK_OF(SU) *s = sk_SU_new_null();
ADD_ALL_TESTS(test_uchar_stack, 4);
ADD_TEST(test_SS_stack);
ADD_TEST(test_SU_stack);
+ ADD_MFAIL_TEST(test_OPENSSL_STRING_deep_copy_mfail);
return 1;
}
CRYPTO_atomic_store_ptr ? 4_1_0 EXIST::FUNCTION:
CRYPTO_atomic_cmp_exch_ptr ? 4_1_0 EXIST::FUNCTION:
EVP_EC_affine2oct ? 4_1_0 EXIST::FUNCTION:
+OPENSSL_sk_set_copy_thunks ? 4_1_0 EXIST::FUNCTION:
SKM_DEFINE_STACK_OF_INTERNAL(${nametype}, ${realtype}, ${plaintype})
#define sk_${nametype}_num(sk) OPENSSL_sk_num(ossl_check_const_${nametype}_sk_type(sk))
#define sk_${nametype}_value(sk, idx) ((${realtype} *)OPENSSL_sk_value(ossl_check_const_${nametype}_sk_type(sk), (idx)))
-#define sk_${nametype}_new(cmp) ((STACK_OF(${nametype}) *)OPENSSL_sk_set_cmp_thunks(OPENSSL_sk_new(ossl_check_${nametype}_compfunc_type(cmp)), sk_${nametype}_cmpfunc_thunk))
-#define sk_${nametype}_new_null() ((STACK_OF(${nametype}) *)OPENSSL_sk_set_thunks(OPENSSL_sk_new_null(), sk_${nametype}_freefunc_thunk))
-#define sk_${nametype}_new_reserve(cmp, n) ((STACK_OF(${nametype}) *)OPENSSL_sk_set_cmp_thunks(OPENSSL_sk_new_reserve(ossl_check_${nametype}_compfunc_type(cmp), (n)), sk_${nametype}_cmpfunc_thunk))
+#define sk_${nametype}_new(cmp) ((STACK_OF(${nametype}) *)OPENSSL_sk_set_copy_thunks(OPENSSL_sk_set_cmp_thunks(OPENSSL_sk_new(ossl_check_${nametype}_compfunc_type(cmp)), sk_${nametype}_cmpfunc_thunk), sk_${nametype}_copyfunc_thunk))
+#define sk_${nametype}_new_null() ((STACK_OF(${nametype}) *)OPENSSL_sk_set_thunks(OPENSSL_sk_set_copy_thunks(OPENSSL_sk_new_null(), sk_${nametype}_copyfunc_thunk), sk_${nametype}_freefunc_thunk))
+#define sk_${nametype}_new_reserve(cmp, n) ((STACK_OF(${nametype}) *)OPENSSL_sk_set_copy_thunks(OPENSSL_sk_set_cmp_thunks(OPENSSL_sk_new_reserve(ossl_check_${nametype}_compfunc_type(cmp), (n)), sk_${nametype}_cmpfunc_thunk), sk_${nametype}_copyfunc_thunk))
#define sk_${nametype}_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_${nametype}_sk_type(sk), (n))
#define sk_${nametype}_free(sk) OPENSSL_sk_free(ossl_check_${nametype}_sk_type(sk))
#define sk_${nametype}_zero(sk) OPENSSL_sk_zero(ossl_check_${nametype}_sk_type(sk))