aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2018-12-26 13:50:27 -0800
committerMark Adler <madler@alumni.caltech.edu>2018-12-26 13:50:27 -0800
commit7c0c75e990ca5395139c148f120042048b0ce091 (patch)
treea852f93466339e316d7df629ec198082f50c92b7
parentf8719f5ae5acdc31d3794ddfea8ac963359de41e (diff)
downloadzlib-7c0c75e990ca5395139c148f120042048b0ce091.tar.gz
zlib-7c0c75e990ca5395139c148f120042048b0ce091.tar.bz2
zlib-7c0c75e990ca5395139c148f120042048b0ce091.zip
Use atomic test and set, if available, for dynamic CRC tables.
-rw-r--r--crc32.c154
1 files changed, 112 insertions, 42 deletions
diff --git a/crc32.c b/crc32.c
index f41dc6d..ed39710 100644
--- a/crc32.c
+++ b/crc32.c
@@ -112,7 +112,6 @@ local z_crc_t x2nmodp OF((z_off64_t n, unsigned k));
112 112
113#ifdef DYNAMIC_CRC_TABLE 113#ifdef DYNAMIC_CRC_TABLE
114 114
115local volatile int crc_table_empty = 1;
116local z_crc_t FAR crc_table[256]; 115local z_crc_t FAR crc_table[256];
117local z_crc_t FAR x2n_table[32]; 116local z_crc_t FAR x2n_table[32];
118local void make_crc_table OF((void)); 117local void make_crc_table OF((void));
@@ -129,6 +128,94 @@ local void make_crc_table OF((void));
129#endif /* MAKECRCH */ 128#endif /* MAKECRCH */
130 129
131/* 130/*
131 Define a once() function depending on the availability of atomics. If this is
132 compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in
133 multiple threads, and if atomics are not available, then get_crc_table() must
134 be called to initialize the tables and must return before any threads are
135 allowed to compute or combine CRCs.
136 */
137
138/* Definition of once functionality. */
139typedef struct once_s once_t;
140local void once OF((once_t *, void (*)(void)));
141
142/* Check for the availability of atomics. */
143#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
144 !defined(__STDC_NO_ATOMICS__)
145
146#include <stdatomic.h>
147
148/* Structure for once(), which must be initialized with ONCE_INIT. */
149struct once_s {
150 atomic_flag begun;
151 atomic_int done;
152};
153#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}
154
155/*
156 Run the provided init() function exactly once, even if multiple threads
157 invoke once() at the same time. The state must be a once_t initialized with
158 ONCE_INIT.
159 */
160local void once(state, init)
161 once_t *state;
162 void (*init)(void);
163{
164 if (!atomic_load(&state->done)) {
165 if (atomic_flag_test_and_set(&state->begun))
166 while (!atomic_load(&state->done))
167 ;
168 else {
169 init();
170 atomic_store(&state->done, 1);
171 }
172 }
173}
174
175#else /* no atomics */
176
177/* Structure for once(), which must be initialized with ONCE_INIT. */
178struct once_s {
179 volatile int begun;
180 volatile int done;
181};
182#define ONCE_INIT {0, 0}
183
184/* Test and set. Alas, not atomic, but tries to minimize the period of
185 vulnerability. */
186local int test_and_set OF((int volatile *));
187local int test_and_set(flag)
188 int volatile *flag;
189{
190 int was;
191
192 was = *flag;
193 *flag = 1;
194 return was;
195}
196
197/* Run the provided init() function once. This is not thread-safe. */
198local void once(state, init)
199 once_t *state;
200 void (*init)(void);
201{
202 if (!state->done) {
203 if (test_and_set(&state->begun))
204 while (!state->done)
205 ;
206 else {
207 init();
208 state->done = 1;
209 }
210 }
211}
212
213#endif
214
215/* State for once(). */
216local once_t made = ONCE_INIT;
217
218/*
132 Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: 219 Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
133 x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. 220 x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
134 221
@@ -155,45 +242,31 @@ local void make_crc_table OF((void));
155 242
156local void make_crc_table() 243local void make_crc_table()
157{ 244{
245 unsigned i, j, n;
158 z_crc_t p; 246 z_crc_t p;
159 static volatile int first = 1; /* flag to limit concurrent making */ 247
160 248 /* initialize the CRC of bytes tables */
161 /* See if another task is already doing this (not thread-safe, but better 249 for (i = 0; i < 256; i++) {
162 than nothing -- significantly reduces duration of vulnerability in 250 p = i;
163 case the advice about DYNAMIC_CRC_TABLE is ignored) */ 251 for (j = 0; j < 8; j++)
164 if (first) { 252 p = p & 1 ? (p >> 1) ^ POLY : p >> 1;
165 unsigned i, j, n; 253 crc_table[i] = p;
166 first = 0;
167
168 /* initialize the CRC of bytes tables */
169 for (i = 0; i < 256; i++) {
170 p = i;
171 for (j = 0; j < 8; j++)
172 p = p & 1 ? (p >> 1) ^ POLY : p >> 1;
173 crc_table[i] = p;
174#ifdef W 254#ifdef W
175 crc_big_table[i] = byte_swap(p); 255 crc_big_table[i] = byte_swap(p);
176#endif 256#endif
177 } 257 }
258
259 /* initialize the x^2^n mod p(x) table */
260 p = (z_crc_t)1 << 30; /* x^1 */
261 x2n_table[0] = p;
262 for (n = 1; n < 32; n++)
263 x2n_table[n] = p = multmodp(p, p);
178 264
179 /* initialize the x^2^n mod p(x) table */
180 p = (z_crc_t)1 << 30; /* x^1 */
181 x2n_table[0] = p;
182 for (n = 1; n < 32; n++)
183 x2n_table[n] = p = multmodp(p, p);
184#ifdef W 265#ifdef W
185 /* initialize the braiding tables -- needs x2n_table[] */ 266 /* initialize the braiding tables -- needs x2n_table[] */
186 braid(crc_braid_table, crc_braid_big_table, N, W); 267 braid(crc_braid_table, crc_braid_big_table, N, W);
187#endif 268#endif
188 269
189 /* mark tables as complete, in case someone else is waiting */
190 crc_table_empty = 0;
191 }
192 else { /* not first */
193 /* wait for the other guy to finish (not efficient, but rare) */
194 while (crc_table_empty)
195 ;
196 }
197#ifdef MAKECRCH 270#ifdef MAKECRCH
198 { 271 {
199 /* 272 /*
@@ -532,13 +605,13 @@ local z_word_t crc_word_big(data)
532#endif /* W */ 605#endif /* W */
533 606
534/* ========================================================================= 607/* =========================================================================
535 * This function can be used by asm versions of crc32() 608 * This function can be used by asm versions of crc32(), and to force the
609 * generation of the CRC tables in a threaded application.
536 */ 610 */
537const z_crc_t FAR * ZEXPORT get_crc_table() 611const z_crc_t FAR * ZEXPORT get_crc_table()
538{ 612{
539#ifdef DYNAMIC_CRC_TABLE 613#ifdef DYNAMIC_CRC_TABLE
540 if (crc_table_empty) 614 once(&made, make_crc_table);
541 make_crc_table();
542#endif /* DYNAMIC_CRC_TABLE */ 615#endif /* DYNAMIC_CRC_TABLE */
543 return (const z_crc_t FAR *)crc_table; 616 return (const z_crc_t FAR *)crc_table;
544} 617}
@@ -553,8 +626,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len)
553 if (buf == Z_NULL) return 0; 626 if (buf == Z_NULL) return 0;
554 627
555#ifdef DYNAMIC_CRC_TABLE 628#ifdef DYNAMIC_CRC_TABLE
556 if (crc_table_empty) 629 once(&made, make_crc_table);
557 make_crc_table();
558#endif /* DYNAMIC_CRC_TABLE */ 630#endif /* DYNAMIC_CRC_TABLE */
559 631
560 /* Pre-condition the CRC */ 632 /* Pre-condition the CRC */
@@ -882,8 +954,7 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
882 z_off64_t len2; 954 z_off64_t len2;
883{ 955{
884#ifdef DYNAMIC_CRC_TABLE 956#ifdef DYNAMIC_CRC_TABLE
885 if (crc_table_empty) 957 once(&made, make_crc_table);
886 make_crc_table();
887#endif /* DYNAMIC_CRC_TABLE */ 958#endif /* DYNAMIC_CRC_TABLE */
888 return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; 959 return multmodp(x2nmodp(len2, 3), crc1) ^ crc2;
889} 960}
@@ -902,8 +973,7 @@ uLong ZEXPORT crc32_combine_gen64(len2)
902 z_off64_t len2; 973 z_off64_t len2;
903{ 974{
904#ifdef DYNAMIC_CRC_TABLE 975#ifdef DYNAMIC_CRC_TABLE
905 if (crc_table_empty) 976 once(&made, make_crc_table);
906 make_crc_table();
907#endif /* DYNAMIC_CRC_TABLE */ 977#endif /* DYNAMIC_CRC_TABLE */
908 return x2nmodp(len2, 3); 978 return x2nmodp(len2, 3);
909} 979}