Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: openssl/patches/fix_lhash_iteration.patch

Issue 57833003: Fix lhash implementation to avoid unwanted resizes during iteration. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/openssl@master
Patch Set: Update to latest upstream version of the patch + update README.Chromium Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « openssl/openssl.config ('k') | openssl/ssl/ssl_sess.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 diff --git a/crypto/conf/conf_api.c b/crypto/conf/conf_api.c
2 index f5fcbb9..9a37bd4 100644
3 --- a/crypto/conf/conf_api.c
4 +++ b/crypto/conf/conf_api.c
5 @@ -225,9 +225,6 @@ void _CONF_free_data(CONF *conf)
6 {
7 if (conf == NULL || conf->data == NULL) return;
8
9 - lh_CONF_VALUE_down_load(conf->data)=0; /* evil thing to make
10 - * sure the 'OPENSSL_free()' works as
11 - * expected */
12 lh_CONF_VALUE_doall_arg(conf->data,
13 LHASH_DOALL_ARG_FN(value_free_hash),
14 LHASH_OF(CONF_VALUE), conf->data);
15 diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c
16 index 47f7480..e5b3cdf 100644
17 --- a/crypto/lhash/lhash.c
18 +++ b/crypto/lhash/lhash.c
19 @@ -94,6 +94,7 @@
20 *
21 * 1.0 eay - First version
22 */
23 +#include <limits.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 @@ -107,6 +108,113 @@ const char lh_version[]="lhash" OPENSSL_VERSION_PTEXT;
28 #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */
29 #define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */
30
31 +/* Maximum number of nodes to guarantee the load computations don't overflow */
32 +#define MAX_LOAD_ITEMS (UINT_MAX / LH_LOAD_MULT)
33 +
34 +/* The field 'iteration_state' is used to hold data to ensure that a hash
35 + * table is not resized during an 'insert' or 'delete' operation performed
36 + * within a lh_doall/lh_doall_arg call.
37 + *
38 + * Conceptually, this records two things:
39 + *
40 + * - A 'depth' count, which is incremented at the start of lh_doall*,
41 + * and decremented just before it returns.
42 + *
43 + * - A 'mutated' boolean flag, which is set in lh_insert() or lh_delete()
44 + * when the operation is performed with a non-0 depth.
45 + *
46 + * The following are helper macros to handle this state in a more explicit
47 + * way.
48 + */
49 +
50 +/* Reset the iteration state to its defaults. */
51 +#define LH_ITERATION_RESET(lh) do { \
52 + (lh)->iteration_state = 0; \
53 + } while (0)
54 +
55 +/* Returns 1 if the hash table is currently being iterated on, 0 otherwise. */
56 +#define LH_ITERATION_IS_ACTIVE(lh) ((lh)->iteration_state >= 2)
57 +
58 +/* Increment iteration depth. This should always be followed by a paired call
59 + * to LH_ITERATION_DECREMENT_DEPTH(). */
60 +#define LH_ITERATION_INCREMENT_DEPTH(lh) do { \
61 + (lh)->iteration_state += 2; \
62 + } while (0)
63 +
64 +/* Decrement iteration depth. This should always be called after a paired call
65 + * to LH_ITERATION_INCREMENT_DEPTH(). */
66 +#define LH_ITERATION_DECREMENT_DEPTH(lh) do { \
67 + (lh)->iteration_state -= 2; \
68 + } while (0)
69 +
70 +/* Return 1 if the iteration 'mutated' flag is set, 0 otherwise. */
71 +#define LH_ITERATION_IS_MUTATED(lh) (((lh)->iteration_state & 1) != 0)
72 +
73 +/* Set the iteration 'mutated' flag to 1. LH_ITERATION_RESET() to reset it. */
74 +#define LH_ITERATION_SET_MUTATED(lh) do { \
75 + (lh)->iteration_state |= 1; \
76 + } while (0)
77 +
78 +/* This macro returns 1 if the hash table should be expanded due to its current
79 + * load, or 0 otherwise. The exact comparison to be performed is expressed by
80 + * the mathematical expression (where '//' denotes division over real numbers):
81 + *
82 + * (num_items // num_nodes) >= (up_load // LOAD_MULT) or
83 + * (num_items * LOAD_MULT // num_nodes) >= up_load.
84 + *
85 + * Given that the C language operator '/' implements integer division, i.e:
86 + * a // b == (a / b) + epsilon (with 0 <= epsilon < 1, for positive a & b)
87 + *
88 + * This can be rewritten as:
89 + * (num_items * LOAD_MULT / num_nodes) + epsilon >= up_load
90 + * (num_items * LOAD_MULT / num_nodes) - up_load >= - epsilon
91 + *
92 + * Let's call 'A' the left-hand side of the equation above, it is an integer
93 + * and:
94 + * - If A >= 0, the expression is true for any value of epsilon.
95 + * - If A <= -1, the expression is also true for any value of epsilon.
96 + *
97 + * In other words, this is equivalent to 'A >= 0', or:
98 + * (num_items * LOAD_MULT / num_nodes) >= up_load
99 + */
100 +#define LH_SHOULD_EXPAND(lh) \
101 + ((lh)->num_items < MAX_LOAD_ITEMS && \
102 + (((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) >= (lh)->up_load))
103 +
104 +/* This macro returns 1 if the hash table should be contracted due to its
105 + * current load, or 0 otherwise. Abbreviated computations are:
106 + *
107 + * (num_items // num_nodes) <= (down_load // LOAD_MULT)
108 + * (num_items * LOAD_MULT // num_nodes) <= down_load
109 + * (num_items * LOAD_MULT / num_nodes) + epsilon <= down_load
110 + * (num_items * LOAD_MULT / num_nodes) - down_load <= -epsilon
111 + *
112 + * Let's call 'B' the left-hand side of the equation above:
113 + * - If B <= -1, the expression is true for any value of epsilon.
114 + * - If B >= 1, the expression is false for any value of epsilon.
115 + * - If B == 0, the expression is true for 'epsilon == 0', and false
116 + * otherwise, which is problematic.
117 + *
118 + * To work around this problem, while keeping the code simple, just change
119 + * the initial expression to use a strict inequality, i.e.:
120 + *
121 + * (num_items // num_nodes) < (down_load // LOAD_MULT)
122 + *
123 + * Which leads to:
124 + * (num_items * LOAD_MULT / num_nodes) - down_load < -epsilon
125 + *
126 + * Then:
127 + * - If 'B <= -1', the expression is true for any value of epsilon.
128 + * - If 'B' >= 0, the expression is false for any value of epsilon,
129 + *
130 + * In other words, this is equivalent to 'B < 0', or:
131 + * (num_items * LOAD_MULT / num_nodes) < down_load
132 + */
133 +#define LH_SHOULD_CONTRACT(lh) \
134 + (((lh)->num_nodes > MIN_NODES) && \
135 + ((lh)->num_items < MAX_LOAD_ITEMS && \
136 + ((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) < (lh)->down_load))
137 +
138 static void expand(_LHASH *lh);
139 static void contract(_LHASH *lh);
140 static LHASH_NODE **getrn(_LHASH *lh, const void *data, unsigned long *rhash);
141 @@ -147,6 +255,7 @@ _LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c)
142 ret->num_hash_comps=0;
143
144 ret->error=0;
145 + LH_ITERATION_RESET(ret);
146 return(ret);
147 err1:
148 OPENSSL_free(ret);
149 @@ -183,7 +292,10 @@ void *lh_insert(_LHASH *lh, void *data)
150 void *ret;
151
152 lh->error=0;
153 - if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))
154 + /* Do not expand the array if the table is being iterated on. */
155 + if (LH_ITERATION_IS_ACTIVE(lh))
156 + LH_ITERATION_SET_MUTATED(lh);
157 + else if (LH_SHOULD_EXPAND(lh))
158 expand(lh);
159
160 rn=getrn(lh,data,&hash);
161 @@ -238,8 +350,10 @@ void *lh_delete(_LHASH *lh, const void *data)
162 }
163
164 lh->num_items--;
165 - if ((lh->num_nodes > MIN_NODES) &&
166 - (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)))
167 + /* Do not contract the array if the table is being iterated on. */
168 + if (LH_ITERATION_IS_ACTIVE(lh))
169 + LH_ITERATION_SET_MUTATED(lh);
170 + else if (LH_SHOULD_CONTRACT(lh))
171 contract(lh);
172
173 return(ret);
174 @@ -276,6 +390,7 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOA LL_FN_TYPE func,
175 if (lh == NULL)
176 return;
177
178 + LH_ITERATION_INCREMENT_DEPTH(lh);
179 /* reverse the order so we search from 'top to bottom'
180 * We were having memory leaks otherwise */
181 for (i=lh->num_nodes-1; i>=0; i--)
182 @@ -283,10 +398,7 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DO ALL_FN_TYPE func,
183 a=lh->b[i];
184 while (a != NULL)
185 {
186 - /* 28/05/91 - eay - n added so items can be deleted
187 - * via lh_doall */
188 - /* 22/05/08 - ben - eh? since a is not passed,
189 - * this should not be needed */
190 + /* note that 'a' can be deleted by the callback */
191 n=a->next;
192 if(use_arg)
193 func_arg(a->data,arg);
194 @@ -295,6 +407,19 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DO ALL_FN_TYPE func,
195 a=n;
196 }
197 }
198 +
199 + LH_ITERATION_DECREMENT_DEPTH(lh);
200 + if (!LH_ITERATION_IS_ACTIVE(lh) && LH_ITERATION_IS_MUTATED(lh))
201 + {
202 + LH_ITERATION_RESET(lh);
203 + /* Resize the buckets array if necessary. Each expand() or
204 + * contract() call will double/halve the size of the array,
205 + * respectively, so call them in a loop. */
206 + while (LH_SHOULD_EXPAND(lh))
207 + expand(lh);
208 + while (LH_SHOULD_CONTRACT(lh))
209 + contract(lh);
210 + }
211 }
212
213 void lh_doall(_LHASH *lh, LHASH_DOALL_FN_TYPE func)
214 diff --git a/crypto/lhash/lhash.h b/crypto/lhash/lhash.h
215 index e7d8763..75386f2 100644
216 --- a/crypto/lhash/lhash.h
217 +++ b/crypto/lhash/lhash.h
218 @@ -163,6 +163,7 @@ typedef struct lhash_st
219 unsigned long num_hash_comps;
220
221 int error;
222 + int iteration_state;
223 } _LHASH; /* Do not use _LHASH directly, use LHASH_OF
224 * and friends */
225
226 diff --git a/crypto/objects/o_names.c b/crypto/objects/o_names.c
227 index 4a548c2..4e18045 100644
228 --- a/crypto/objects/o_names.c
229 +++ b/crypto/objects/o_names.c
230 @@ -350,13 +350,9 @@ static void name_funcs_free(NAME_FUNCS *ptr)
231
232 void OBJ_NAME_cleanup(int type)
233 {
234 - unsigned long down_load;
235 -
236 if (names_lh == NULL) return;
237
238 free_type=type;
239 - down_load=lh_OBJ_NAME_down_load(names_lh);
240 - lh_OBJ_NAME_down_load(names_lh)=0;
241
242 lh_OBJ_NAME_doall(names_lh,LHASH_DOALL_FN(names_lh_free));
243 if (type < 0)
244 @@ -366,7 +362,5 @@ void OBJ_NAME_cleanup(int type)
245 names_lh=NULL;
246 name_funcs_stack = NULL;
247 }
248 - else
249 - lh_OBJ_NAME_down_load(names_lh)=down_load;
250 }
251
252 diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c
253 index 8a342ba..ef0512a 100644
254 --- a/crypto/objects/obj_dat.c
255 +++ b/crypto/objects/obj_dat.c
256 @@ -227,7 +227,6 @@ void OBJ_cleanup(void)
257 return ;
258 }
259 if (added == NULL) return;
260 - lh_ADDED_OBJ_down_load(added) = 0;
261 lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup1)); /* zero counters */
262 lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup2)); /* set counters */
263 lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup3)); /* free objects */
264 diff --git a/include/openssl/lhash.h b/include/openssl/lhash.h
265 index e7d8763..75386f2 100644
266 --- a/include/openssl/lhash.h
267 +++ b/include/openssl/lhash.h
268 @@ -163,6 +163,7 @@ typedef struct lhash_st
269 unsigned long num_hash_comps;
270
271 int error;
272 + int iteration_state;
273 } _LHASH; /* Do not use _LHASH directly, use LHASH_OF
274 * and friends */
275
276 diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
277 index 920b763..447a37e 100644
278 --- a/ssl/ssl_sess.c
279 +++ b/ssl/ssl_sess.c
280 @@ -999,11 +999,8 @@ void SSL_CTX_flush_sessions(SSL_CTX *s, long t)
281 if (tp.cache == NULL) return;
282 tp.time=t;
283 CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
284 - i=CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load;
285 - CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load=0;
286 lh_SSL_SESSION_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout),
287 TIMEOUT_PARAM, &tp);
288 - CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load=i;
289 CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
290 }
291
OLDNEW
« no previous file with comments | « openssl/openssl.config ('k') | openssl/ssl/ssl_sess.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698