Skip to content

Commit d88c43a

Browse files
bob-beckpaulidale
authored andcommitted
Ensure that empty or 1 element stacks are always sorted.
Matt noticed "It's kind of weird that we are forced to call sort on a newly created and empty stack. It feels like an empty stack should have the "sorted" flag by default on creation" I am incluined to agree. This change ensures tht empty or 1 element stacks are marked as sorted, as per the existing comment in the file. Since this involved changing the various duplication routines to also ensure that sorted was preserved for such stacks, I also noticed the duplication code was largely duplicated. I took the opportunity to deduplicate the duplication code while making these changes. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Paul Dale <ppzgs1@gmail.com> (Merged from openssl#28509)
1 parent a5eaa0e commit d88c43a

2 files changed

Lines changed: 87 additions & 66 deletions

File tree

crypto/stack/stack.c

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,54 @@ OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk,
3838
{
3939
OPENSSL_sk_compfunc old = sk->comp;
4040

41-
if (sk->comp != c)
41+
if (sk->comp != c && sk->num > 1)
4242
sk->sorted = 0;
4343
sk->comp = c;
4444

4545
return old;
4646
}
4747

48-
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
48+
static OPENSSL_STACK *internal_copy(const OPENSSL_STACK *sk,
49+
OPENSSL_sk_copyfunc copy_func,
50+
OPENSSL_sk_freefunc free_func)
4951
{
5052
OPENSSL_STACK *ret;
53+
int i;
5154

52-
if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
55+
if ((ret = OPENSSL_sk_new_null()) == NULL)
5356
goto err;
5457

55-
if (sk == NULL) {
56-
ret->num = 0;
57-
ret->sorted = 0;
58-
ret->comp = NULL;
59-
} else {
60-
/* direct structure assignment */
61-
*ret = *sk;
62-
}
58+
if (sk == NULL)
59+
goto done;
6360

64-
if (sk == NULL || sk->num == 0) {
65-
/* postpone |ret->data| allocation */
66-
ret->data = NULL;
67-
ret->num_alloc = 0;
68-
return ret;
69-
}
61+
/* direct structure assignment */
62+
*ret = *sk;
63+
ret->data = NULL;
64+
ret->num_alloc = 0;
65+
66+
if (ret->num == 0)
67+
goto done; /* nothing to copy */
7068

71-
/* duplicate |sk->data| content */
72-
ret->data = OPENSSL_malloc_array(sk->num_alloc, sizeof(*ret->data));
69+
ret->num_alloc = ret->num > min_nodes ? ret->num : min_nodes;
70+
ret->data = OPENSSL_calloc(ret->num_alloc, sizeof(*ret->data));
7371
if (ret->data == NULL)
7472
goto err;
75-
memcpy(ret->data, sk->data, sizeof(void *) * sk->num);
73+
if (copy_func == NULL) {
74+
memcpy(ret->data, sk->data, sizeof(*ret->data) * ret->num);
75+
} else {
76+
for (i = 0; i < ret->num; ++i) {
77+
if (sk->data[i] == NULL)
78+
continue;
79+
if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {
80+
while (--i >= 0)
81+
if (ret->data[i] != NULL)
82+
free_func((void *)ret->data[i]);
83+
goto err;
84+
}
85+
}
86+
}
87+
88+
done:
7689
return ret;
7790

7891
err:
@@ -84,48 +97,12 @@ OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
8497
OPENSSL_sk_copyfunc copy_func,
8598
OPENSSL_sk_freefunc free_func)
8699
{
87-
OPENSSL_STACK *ret;
88-
int i;
89-
90-
if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
91-
goto err;
92-
93-
if (sk == NULL) {
94-
ret->num = 0;
95-
ret->sorted = 0;
96-
ret->comp = NULL;
97-
} else {
98-
/* direct structure assignment */
99-
*ret = *sk;
100-
}
101-
102-
if (sk == NULL || sk->num == 0) {
103-
/* postpone |ret| data allocation */
104-
ret->data = NULL;
105-
ret->num_alloc = 0;
106-
return ret;
107-
}
108-
109-
ret->num_alloc = sk->num > min_nodes ? sk->num : min_nodes;
110-
ret->data = OPENSSL_calloc(ret->num_alloc, sizeof(*ret->data));
111-
if (ret->data == NULL)
112-
goto err;
113-
114-
for (i = 0; i < ret->num; ++i) {
115-
if (sk->data[i] == NULL)
116-
continue;
117-
if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {
118-
while (--i >= 0)
119-
if (ret->data[i] != NULL)
120-
free_func((void *)ret->data[i]);
121-
goto err;
122-
}
123-
}
124-
return ret;
100+
return internal_copy(sk, copy_func, free_func);
101+
}
125102

126-
err:
127-
OPENSSL_sk_free(ret);
128-
return NULL;
103+
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
104+
{
105+
return internal_copy(sk, NULL, NULL);
129106
}
130107

131108
OPENSSL_STACK *OPENSSL_sk_new_null(void)
@@ -232,6 +209,7 @@ OPENSSL_STACK *OPENSSL_sk_new_reserve(OPENSSL_sk_compfunc c, int n)
232209
return NULL;
233210

234211
st->comp = c;
212+
st->sorted = 1; /* empty or single-element stack is considered sorted */
235213

236214
if (n <= 0)
237215
return st;
@@ -286,7 +264,7 @@ int OPENSSL_sk_insert(OPENSSL_STACK *st, const void *data, int loc)
286264
st->data[loc] = data;
287265
}
288266
st->num++;
289-
st->sorted = 0;
267+
st->sorted = st->num <= 1;
290268
return st->num;
291269
}
292270

@@ -298,6 +276,7 @@ static ossl_inline void *internal_delete(OPENSSL_STACK *st, int loc)
298276
memmove(&st->data[loc], &st->data[loc + 1],
299277
sizeof(st->data[0]) * (st->num - loc - 1));
300278
st->num--;
279+
st->sorted = st->sorted || st->num <= 1;
301280

302281
return (void *)ret;
303282
}
@@ -487,7 +466,7 @@ void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data)
487466
return NULL;
488467
}
489468
st->data[i] = data;
490-
st->sorted = 0;
469+
st->sorted = st->num <= 1;
491470
return (void *)st->data[i];
492471
}
493472

test/stack_test.c

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ static int int_compare(const int *const *a, const int *const *b)
5050
return 0;
5151
}
5252

53+
static int int_compare_backward(const int *const *a, const int *const *b)
54+
{
55+
if (**a > **b)
56+
return -1;
57+
if (**a < **b)
58+
return 1;
59+
return 0;
60+
}
61+
5362
static int test_int_stack(int reserve)
5463
{
5564
static int v[] = { 1, 2, -4, 16, 999, 1, -173, 1, 9 };
@@ -90,6 +99,9 @@ static int test_int_stack(int reserve)
9099

91100
/* Check push and num */
92101
for (i = 0; i < n; i++) {
102+
/* Empty or single element stack should be sorted */
103+
if ((i == 0 || i == 1) && !TEST_true(sk_sint_is_sorted(s)))
104+
goto end;
93105
if (!TEST_int_eq(sk_sint_num(s), i)) {
94106
TEST_info("int stack size %d", i);
95107
goto end;
@@ -134,9 +146,18 @@ static int test_int_stack(int reserve)
134146
/* sorting */
135147
if (!TEST_false(sk_sint_is_sorted(s)))
136148
goto end;
149+
(void)sk_sint_set_cmp_func(s, &int_compare_backward);
150+
sk_sint_sort(s);
151+
if (!TEST_true(sk_sint_is_sorted(s))) /* should be sorted */
152+
goto end;
153+
(void)sk_sint_set_cmp_func(s, &int_compare_backward);
154+
if (!TEST_true(sk_sint_is_sorted(s))) /* should still be sorted */
155+
goto end;
137156
(void)sk_sint_set_cmp_func(s, &int_compare);
157+
if (!TEST_false(sk_sint_is_sorted(s))) /* should no longer be sorted */
158+
goto end;
138159
sk_sint_sort(s);
139-
if (!TEST_true(sk_sint_is_sorted(s)))
160+
if (!TEST_true(sk_sint_is_sorted(s))) /* now should be sorted again */
140161
goto end;
141162

142163
/* find sorted -- the value is matched so we don't need to locate it */
@@ -178,7 +199,7 @@ static int test_uchar_stack(int reserve)
178199
{
179200
static const unsigned char v[] = { 1, 3, 7, 5, 255, 0 };
180201
const int n = OSSL_NELEM(v);
181-
STACK_OF(uchar) *s = sk_uchar_new(&uchar_compare), *r = NULL;
202+
STACK_OF(uchar) *s = sk_uchar_new(&uchar_compare), *r = NULL, *q = NULL;
182203
int i;
183204
int testresult = 0;
184205

@@ -205,19 +226,40 @@ static int test_uchar_stack(int reserve)
205226
r = sk_uchar_dup(s);
206227
if (!TEST_int_eq(sk_uchar_num(r), n))
207228
goto end;
229+
q = sk_uchar_dup(s);
230+
if (!TEST_int_eq(sk_uchar_num(q), n))
231+
goto end;
208232
sk_uchar_sort(r);
233+
sk_uchar_sort(q);
209234

210235
/* pop */
211-
for (i = 0; i < n; i++)
236+
for (i = 0; i < n; i++) {
212237
if (!TEST_ptr_eq(sk_uchar_pop(s), v + i)) {
213238
TEST_info("uchar pop %d", i);
214239
goto end;
215240
}
241+
/* Previously unsorted stack of more than 1 element remains unsorted */
242+
if (i < n - 2 && !TEST_false(sk_uchar_is_sorted(s)))
243+
goto end;
244+
/* A single or zero element stack should be sorted */
245+
if (i > n - 2 && !TEST_true(sk_uchar_is_sorted(s)))
246+
goto end;
247+
}
216248

217249
/* free -- we rely on the debug malloc to detect leakage here */
218250
sk_uchar_free(s);
219251
s = NULL;
220252

253+
/* pop */
254+
for (i = 0; i < n; i++) {
255+
/* A sorted stack should remain sorted */
256+
if (!TEST_true(sk_uchar_is_sorted(q)))
257+
goto end;
258+
}
259+
/* free -- we rely on the debug malloc to detect leakage here */
260+
sk_uchar_free(q);
261+
q = NULL;
262+
221263
/* dup again */
222264
if (!TEST_int_eq(sk_uchar_num(r), n))
223265
goto end;

0 commit comments

Comments
 (0)