1*e0c4386eSCy Schubert /*
2*e0c4386eSCy Schubert * Copyright 2017-2020 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
4*e0c4386eSCy Schubert *
5*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
6*e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
7*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
8*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
9*e0c4386eSCy Schubert */
10*e0c4386eSCy Schubert
11*e0c4386eSCy Schubert #include <stdio.h>
12*e0c4386eSCy Schubert #include <string.h>
13*e0c4386eSCy Schubert
14*e0c4386eSCy Schubert #include <openssl/opensslconf.h>
15*e0c4386eSCy Schubert #include <openssl/lhash.h>
16*e0c4386eSCy Schubert #include <openssl/err.h>
17*e0c4386eSCy Schubert #include <openssl/crypto.h>
18*e0c4386eSCy Schubert
19*e0c4386eSCy Schubert #include "internal/nelem.h"
20*e0c4386eSCy Schubert #include "testutil.h"
21*e0c4386eSCy Schubert
22*e0c4386eSCy Schubert /*
23*e0c4386eSCy Schubert * The macros below generate unused functions which error out one of the clang
24*e0c4386eSCy Schubert * builds. We disable this check here.
25*e0c4386eSCy Schubert */
26*e0c4386eSCy Schubert #ifdef __clang__
27*e0c4386eSCy Schubert #pragma clang diagnostic ignored "-Wunused-function"
28*e0c4386eSCy Schubert #endif
29*e0c4386eSCy Schubert
30*e0c4386eSCy Schubert DEFINE_LHASH_OF(int);
31*e0c4386eSCy Schubert
32*e0c4386eSCy Schubert static int int_tests[] = { 65537, 13, 1, 3, -5, 6, 7, 4, -10, -12, -14, 22, 9,
33*e0c4386eSCy Schubert -17, 16, 17, -23, 35, 37, 173, 11 };
34*e0c4386eSCy Schubert static const unsigned int n_int_tests = OSSL_NELEM(int_tests);
35*e0c4386eSCy Schubert static short int_found[OSSL_NELEM(int_tests)];
36*e0c4386eSCy Schubert static short int_not_found;
37*e0c4386eSCy Schubert
int_hash(const int * p)38*e0c4386eSCy Schubert static unsigned long int int_hash(const int *p)
39*e0c4386eSCy Schubert {
40*e0c4386eSCy Schubert return 3 & *p; /* To force collisions */
41*e0c4386eSCy Schubert }
42*e0c4386eSCy Schubert
int_cmp(const int * p,const int * q)43*e0c4386eSCy Schubert static int int_cmp(const int *p, const int *q)
44*e0c4386eSCy Schubert {
45*e0c4386eSCy Schubert return *p != *q;
46*e0c4386eSCy Schubert }
47*e0c4386eSCy Schubert
int_find(int n)48*e0c4386eSCy Schubert static int int_find(int n)
49*e0c4386eSCy Schubert {
50*e0c4386eSCy Schubert unsigned int i;
51*e0c4386eSCy Schubert
52*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
53*e0c4386eSCy Schubert if (int_tests[i] == n)
54*e0c4386eSCy Schubert return i;
55*e0c4386eSCy Schubert return -1;
56*e0c4386eSCy Schubert }
57*e0c4386eSCy Schubert
int_doall(int * v)58*e0c4386eSCy Schubert static void int_doall(int *v)
59*e0c4386eSCy Schubert {
60*e0c4386eSCy Schubert const int n = int_find(*v);
61*e0c4386eSCy Schubert
62*e0c4386eSCy Schubert if (n < 0)
63*e0c4386eSCy Schubert int_not_found++;
64*e0c4386eSCy Schubert else
65*e0c4386eSCy Schubert int_found[n]++;
66*e0c4386eSCy Schubert }
67*e0c4386eSCy Schubert
int_doall_arg(int * p,short * f)68*e0c4386eSCy Schubert static void int_doall_arg(int *p, short *f)
69*e0c4386eSCy Schubert {
70*e0c4386eSCy Schubert const int n = int_find(*p);
71*e0c4386eSCy Schubert
72*e0c4386eSCy Schubert if (n < 0)
73*e0c4386eSCy Schubert int_not_found++;
74*e0c4386eSCy Schubert else
75*e0c4386eSCy Schubert f[n]++;
76*e0c4386eSCy Schubert }
77*e0c4386eSCy Schubert
78*e0c4386eSCy Schubert IMPLEMENT_LHASH_DOALL_ARG(int, short);
79*e0c4386eSCy Schubert
test_int_lhash(void)80*e0c4386eSCy Schubert static int test_int_lhash(void)
81*e0c4386eSCy Schubert {
82*e0c4386eSCy Schubert static struct {
83*e0c4386eSCy Schubert int data;
84*e0c4386eSCy Schubert int null;
85*e0c4386eSCy Schubert } dels[] = {
86*e0c4386eSCy Schubert { 65537, 0 },
87*e0c4386eSCy Schubert { 173, 0 },
88*e0c4386eSCy Schubert { 999, 1 },
89*e0c4386eSCy Schubert { 37, 0 },
90*e0c4386eSCy Schubert { 1, 0 },
91*e0c4386eSCy Schubert { 34, 1 }
92*e0c4386eSCy Schubert };
93*e0c4386eSCy Schubert const unsigned int n_dels = OSSL_NELEM(dels);
94*e0c4386eSCy Schubert LHASH_OF(int) *h = lh_int_new(&int_hash, &int_cmp);
95*e0c4386eSCy Schubert unsigned int i;
96*e0c4386eSCy Schubert int testresult = 0, j, *p;
97*e0c4386eSCy Schubert
98*e0c4386eSCy Schubert if (!TEST_ptr(h))
99*e0c4386eSCy Schubert goto end;
100*e0c4386eSCy Schubert
101*e0c4386eSCy Schubert /* insert */
102*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
103*e0c4386eSCy Schubert if (!TEST_ptr_null(lh_int_insert(h, int_tests + i))) {
104*e0c4386eSCy Schubert TEST_info("int insert %d", i);
105*e0c4386eSCy Schubert goto end;
106*e0c4386eSCy Schubert }
107*e0c4386eSCy Schubert
108*e0c4386eSCy Schubert /* num_items */
109*e0c4386eSCy Schubert if (!TEST_int_eq(lh_int_num_items(h), n_int_tests))
110*e0c4386eSCy Schubert goto end;
111*e0c4386eSCy Schubert
112*e0c4386eSCy Schubert /* retrieve */
113*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
114*e0c4386eSCy Schubert if (!TEST_int_eq(*lh_int_retrieve(h, int_tests + i), int_tests[i])) {
115*e0c4386eSCy Schubert TEST_info("lhash int retrieve value %d", i);
116*e0c4386eSCy Schubert goto end;
117*e0c4386eSCy Schubert }
118*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
119*e0c4386eSCy Schubert if (!TEST_ptr_eq(lh_int_retrieve(h, int_tests + i), int_tests + i)) {
120*e0c4386eSCy Schubert TEST_info("lhash int retrieve address %d", i);
121*e0c4386eSCy Schubert goto end;
122*e0c4386eSCy Schubert }
123*e0c4386eSCy Schubert j = 1;
124*e0c4386eSCy Schubert if (!TEST_ptr_eq(lh_int_retrieve(h, &j), int_tests + 2))
125*e0c4386eSCy Schubert goto end;
126*e0c4386eSCy Schubert
127*e0c4386eSCy Schubert /* replace */
128*e0c4386eSCy Schubert j = 13;
129*e0c4386eSCy Schubert if (!TEST_ptr(p = lh_int_insert(h, &j)))
130*e0c4386eSCy Schubert goto end;
131*e0c4386eSCy Schubert if (!TEST_ptr_eq(p, int_tests + 1))
132*e0c4386eSCy Schubert goto end;
133*e0c4386eSCy Schubert if (!TEST_ptr_eq(lh_int_retrieve(h, int_tests + 1), &j))
134*e0c4386eSCy Schubert goto end;
135*e0c4386eSCy Schubert
136*e0c4386eSCy Schubert /* do_all */
137*e0c4386eSCy Schubert memset(int_found, 0, sizeof(int_found));
138*e0c4386eSCy Schubert int_not_found = 0;
139*e0c4386eSCy Schubert lh_int_doall(h, &int_doall);
140*e0c4386eSCy Schubert if (!TEST_int_eq(int_not_found, 0)) {
141*e0c4386eSCy Schubert TEST_info("lhash int doall encountered a not found condition");
142*e0c4386eSCy Schubert goto end;
143*e0c4386eSCy Schubert }
144*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
145*e0c4386eSCy Schubert if (!TEST_int_eq(int_found[i], 1)) {
146*e0c4386eSCy Schubert TEST_info("lhash int doall %d", i);
147*e0c4386eSCy Schubert goto end;
148*e0c4386eSCy Schubert }
149*e0c4386eSCy Schubert
150*e0c4386eSCy Schubert /* do_all_arg */
151*e0c4386eSCy Schubert memset(int_found, 0, sizeof(int_found));
152*e0c4386eSCy Schubert int_not_found = 0;
153*e0c4386eSCy Schubert lh_int_doall_short(h, int_doall_arg, int_found);
154*e0c4386eSCy Schubert if (!TEST_int_eq(int_not_found, 0)) {
155*e0c4386eSCy Schubert TEST_info("lhash int doall arg encountered a not found condition");
156*e0c4386eSCy Schubert goto end;
157*e0c4386eSCy Schubert }
158*e0c4386eSCy Schubert for (i = 0; i < n_int_tests; i++)
159*e0c4386eSCy Schubert if (!TEST_int_eq(int_found[i], 1)) {
160*e0c4386eSCy Schubert TEST_info("lhash int doall arg %d", i);
161*e0c4386eSCy Schubert goto end;
162*e0c4386eSCy Schubert }
163*e0c4386eSCy Schubert
164*e0c4386eSCy Schubert /* delete */
165*e0c4386eSCy Schubert for (i = 0; i < n_dels; i++) {
166*e0c4386eSCy Schubert const int b = lh_int_delete(h, &dels[i].data) == NULL;
167*e0c4386eSCy Schubert if (!TEST_int_eq(b ^ dels[i].null, 0)) {
168*e0c4386eSCy Schubert TEST_info("lhash int delete %d", i);
169*e0c4386eSCy Schubert goto end;
170*e0c4386eSCy Schubert }
171*e0c4386eSCy Schubert }
172*e0c4386eSCy Schubert
173*e0c4386eSCy Schubert /* error */
174*e0c4386eSCy Schubert if (!TEST_int_eq(lh_int_error(h), 0))
175*e0c4386eSCy Schubert goto end;
176*e0c4386eSCy Schubert
177*e0c4386eSCy Schubert testresult = 1;
178*e0c4386eSCy Schubert end:
179*e0c4386eSCy Schubert lh_int_free(h);
180*e0c4386eSCy Schubert return testresult;
181*e0c4386eSCy Schubert }
182*e0c4386eSCy Schubert
stress_hash(const int * p)183*e0c4386eSCy Schubert static unsigned long int stress_hash(const int *p)
184*e0c4386eSCy Schubert {
185*e0c4386eSCy Schubert return *p;
186*e0c4386eSCy Schubert }
187*e0c4386eSCy Schubert
test_stress(void)188*e0c4386eSCy Schubert static int test_stress(void)
189*e0c4386eSCy Schubert {
190*e0c4386eSCy Schubert LHASH_OF(int) *h = lh_int_new(&stress_hash, &int_cmp);
191*e0c4386eSCy Schubert const unsigned int n = 2500000;
192*e0c4386eSCy Schubert unsigned int i;
193*e0c4386eSCy Schubert int testresult = 0, *p;
194*e0c4386eSCy Schubert
195*e0c4386eSCy Schubert if (!TEST_ptr(h))
196*e0c4386eSCy Schubert goto end;
197*e0c4386eSCy Schubert
198*e0c4386eSCy Schubert /* insert */
199*e0c4386eSCy Schubert for (i = 0; i < n; i++) {
200*e0c4386eSCy Schubert p = OPENSSL_malloc(sizeof(i));
201*e0c4386eSCy Schubert if (!TEST_ptr(p)) {
202*e0c4386eSCy Schubert TEST_info("lhash stress out of memory %d", i);
203*e0c4386eSCy Schubert goto end;
204*e0c4386eSCy Schubert }
205*e0c4386eSCy Schubert *p = 3 * i + 1;
206*e0c4386eSCy Schubert lh_int_insert(h, p);
207*e0c4386eSCy Schubert }
208*e0c4386eSCy Schubert
209*e0c4386eSCy Schubert /* num_items */
210*e0c4386eSCy Schubert if (!TEST_int_eq(lh_int_num_items(h), n))
211*e0c4386eSCy Schubert goto end;
212*e0c4386eSCy Schubert
213*e0c4386eSCy Schubert TEST_info("hash full statistics:");
214*e0c4386eSCy Schubert OPENSSL_LH_stats_bio((OPENSSL_LHASH *)h, bio_err);
215*e0c4386eSCy Schubert TEST_note("hash full node usage:");
216*e0c4386eSCy Schubert OPENSSL_LH_node_usage_stats_bio((OPENSSL_LHASH *)h, bio_err);
217*e0c4386eSCy Schubert
218*e0c4386eSCy Schubert /* delete in a different order */
219*e0c4386eSCy Schubert for (i = 0; i < n; i++) {
220*e0c4386eSCy Schubert const int j = (7 * i + 4) % n * 3 + 1;
221*e0c4386eSCy Schubert
222*e0c4386eSCy Schubert if (!TEST_ptr(p = lh_int_delete(h, &j))) {
223*e0c4386eSCy Schubert TEST_info("lhash stress delete %d\n", i);
224*e0c4386eSCy Schubert goto end;
225*e0c4386eSCy Schubert }
226*e0c4386eSCy Schubert if (!TEST_int_eq(*p, j)) {
227*e0c4386eSCy Schubert TEST_info("lhash stress bad value %d", i);
228*e0c4386eSCy Schubert goto end;
229*e0c4386eSCy Schubert }
230*e0c4386eSCy Schubert OPENSSL_free(p);
231*e0c4386eSCy Schubert }
232*e0c4386eSCy Schubert
233*e0c4386eSCy Schubert TEST_info("hash empty statistics:");
234*e0c4386eSCy Schubert OPENSSL_LH_stats_bio((OPENSSL_LHASH *)h, bio_err);
235*e0c4386eSCy Schubert TEST_note("hash empty node usage:");
236*e0c4386eSCy Schubert OPENSSL_LH_node_usage_stats_bio((OPENSSL_LHASH *)h, bio_err);
237*e0c4386eSCy Schubert
238*e0c4386eSCy Schubert testresult = 1;
239*e0c4386eSCy Schubert end:
240*e0c4386eSCy Schubert lh_int_free(h);
241*e0c4386eSCy Schubert return testresult;
242*e0c4386eSCy Schubert }
243*e0c4386eSCy Schubert
setup_tests(void)244*e0c4386eSCy Schubert int setup_tests(void)
245*e0c4386eSCy Schubert {
246*e0c4386eSCy Schubert ADD_TEST(test_int_lhash);
247*e0c4386eSCy Schubert ADD_TEST(test_stress);
248*e0c4386eSCy Schubert return 1;
249*e0c4386eSCy Schubert }
250