Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
26 | pmbaty | 1 | /* ucl_init.c -- initialization of the UCL library |
2 | |||
3 | This file is part of the UCL data compression library. |
||
4 | |||
5 | Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer |
||
6 | All Rights Reserved. |
||
7 | |||
8 | The UCL library is free software; you can redistribute it and/or |
||
9 | modify it under the terms of the GNU General Public License as |
||
10 | published by the Free Software Foundation; either version 2 of |
||
11 | the License, or (at your option) any later version. |
||
12 | |||
13 | The UCL library is distributed in the hope that it will be useful, |
||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | GNU General Public License for more details. |
||
17 | |||
18 | You should have received a copy of the GNU General Public License |
||
19 | along with the UCL library; see the file COPYING. |
||
20 | If not, write to the Free Software Foundation, Inc., |
||
21 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
22 | |||
23 | Markus F.X.J. Oberhumer |
||
24 | <markus@oberhumer.com> |
||
25 | http://www.oberhumer.com/opensource/ucl/ |
||
26 | */ |
||
27 | |||
28 | |||
29 | #include "ucl_conf.h" |
||
30 | |||
31 | |||
32 | /*********************************************************************** |
||
33 | // Runtime check of the assumptions about the size of builtin types, |
||
34 | // memory model, byte order and other low-level constructs. |
||
35 | // |
||
36 | // We are really paranoid here - UCL should either fail |
||
37 | // at startup or not at all. |
||
38 | // |
||
39 | // Because of inlining much of this evaluates to nothing at compile time. |
||
40 | // |
||
41 | // And while many of the tests seem highly obvious and redundant they are |
||
42 | // here to catch compiler/optimizer bugs. Yes, these do exist. |
||
43 | ************************************************************************/ |
||
44 | |||
45 | static ucl_bool schedule_insns_bug(void); /* avoid inlining */ |
||
46 | static ucl_bool strength_reduce_bug(int *); /* avoid inlining */ |
||
47 | |||
48 | |||
49 | #if 0 || defined(UCL_DEBUG) |
||
50 | #include <stdio.h> |
||
51 | static ucl_bool __ucl_assert_fail(const char *s, unsigned line) |
||
52 | { |
||
53 | #if defined(__palmos__) |
||
54 | printf("UCL assertion failed in line %u: '%s'\n",line,s); |
||
55 | #else |
||
56 | fprintf(stderr,"UCL assertion failed in line %u: '%s'\n",line,s); |
||
57 | #endif |
||
58 | return 0; |
||
59 | } |
||
60 | # define __ucl_assert(x) ((x) ? 1 : __ucl_assert_fail(#x,__LINE__)) |
||
61 | #else |
||
62 | # define __ucl_assert(x) ((x) ? 1 : 0) |
||
63 | #endif |
||
64 | |||
65 | |||
66 | /*********************************************************************** |
||
67 | // basic_check - compile time assertions |
||
68 | ************************************************************************/ |
||
69 | |||
70 | #if 1 |
||
71 | |||
72 | #undef ACCCHK_ASSERT |
||
73 | #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT_HEADER(expr) |
||
74 | |||
75 | #include "acc/acc_chk.ch" |
||
76 | |||
77 | ACCCHK_ASSERT_IS_SIGNED_T(ucl_int) |
||
78 | ACCCHK_ASSERT_IS_UNSIGNED_T(ucl_uint) |
||
79 | |||
80 | ACCCHK_ASSERT_IS_SIGNED_T(ucl_int32) |
||
81 | ACCCHK_ASSERT_IS_UNSIGNED_T(ucl_uint32) |
||
82 | ACCCHK_ASSERT((UCL_UINT32_C(1) << (int)(8*sizeof(UCL_UINT32_C(1))-1)) > 0) |
||
83 | |||
84 | ACCCHK_ASSERT_IS_UNSIGNED_T(ucl_uintptr_t) |
||
85 | ACCCHK_ASSERT(sizeof(ucl_uintptr_t) >= sizeof(ucl_voidp)) |
||
86 | |||
87 | #endif |
||
88 | #undef ACCCHK_ASSERT |
||
89 | |||
90 | |||
91 | /*********************************************************************** |
||
92 | // |
||
93 | ************************************************************************/ |
||
94 | |||
95 | static ucl_bool ptr_check(void) |
||
96 | { |
||
97 | ucl_bool r = 1; |
||
98 | int i; |
||
99 | unsigned char _wrkmem[10 * sizeof(ucl_bytep) + sizeof(ucl_align_t)]; |
||
100 | ucl_bytep wrkmem; |
||
101 | ucl_bytepp dict; |
||
102 | unsigned char x[4 * sizeof(ucl_align_t)]; |
||
103 | long d; |
||
104 | ucl_align_t a; |
||
105 | |||
106 | for (i = 0; i < (int) sizeof(x); i++) |
||
107 | x[i] = UCL_BYTE(i); |
||
108 | |||
109 | wrkmem = UCL_PTR_ALIGN_UP((ucl_bytep)_wrkmem, sizeof(ucl_align_t)); |
||
110 | |||
111 | dict = (ucl_bytepp) (ucl_voidp) wrkmem; |
||
112 | |||
113 | d = (long) ((const ucl_bytep) dict - (const ucl_bytep) _wrkmem); |
||
114 | r &= __ucl_assert(d >= 0); |
||
115 | r &= __ucl_assert(d < (long) sizeof(ucl_align_t)); |
||
116 | |||
117 | /* this may seem obvious, but some compilers incorrectly inline memset */ |
||
118 | memset(&a,0xff,sizeof(a)); |
||
119 | r &= __ucl_assert(a.a_ushort == USHRT_MAX); |
||
120 | r &= __ucl_assert(a.a_uint == UINT_MAX); |
||
121 | r &= __ucl_assert(a.a_ulong == ULONG_MAX); |
||
122 | r &= __ucl_assert(a.a_ucl_uint == UCL_UINT_MAX); |
||
123 | |||
124 | /* sanity check of the memory model */ |
||
125 | if (r == 1) |
||
126 | { |
||
127 | for (i = 0; i < 8; i++) |
||
128 | r &= __ucl_assert((const ucl_voidp) (&dict[i]) == (const ucl_voidp) (&wrkmem[i * sizeof(ucl_bytep)])); |
||
129 | } |
||
130 | |||
131 | /* check that NULL == 0 */ |
||
132 | memset(&a,0,sizeof(a)); |
||
133 | r &= __ucl_assert(a.a_char_p == NULL); |
||
134 | r &= __ucl_assert(a.a_ucl_bytep == NULL); |
||
135 | |||
136 | /* check that the pointer constructs work as expected */ |
||
137 | if (r == 1) |
||
138 | { |
||
139 | unsigned k = 1; |
||
140 | const unsigned n = (unsigned) sizeof(ucl_uint32); |
||
141 | ucl_bytep p0; |
||
142 | ucl_bytep p1; |
||
143 | |||
144 | k += __ucl_align_gap(&x[k],n); |
||
145 | p0 = (ucl_bytep) &x[k]; |
||
146 | #if defined(PTR_LINEAR) |
||
147 | r &= __ucl_assert((PTR_LINEAR(p0) & (n-1)) == 0); |
||
148 | #else |
||
149 | r &= __ucl_assert(n == 4); |
||
150 | r &= __ucl_assert(PTR_ALIGNED_4(p0)); |
||
151 | #endif |
||
152 | |||
153 | r &= __ucl_assert(k >= 1); |
||
154 | p1 = (ucl_bytep) &x[1]; |
||
155 | r &= __ucl_assert(PTR_GE(p0,p1)); |
||
156 | |||
157 | r &= __ucl_assert(k < 1u+n); |
||
158 | p1 = (ucl_bytep) &x[1+n]; |
||
159 | r &= __ucl_assert(PTR_LT(p0,p1)); |
||
160 | |||
161 | /* now check that aligned memory access doesn't core dump */ |
||
162 | if (r == 1) |
||
163 | { |
||
164 | ucl_uint32 v0, v1; |
||
165 | v0 = * (ucl_uint32p) (ucl_voidp) &x[k]; |
||
166 | v1 = * (ucl_uint32p) (ucl_voidp) &x[k+n]; |
||
167 | r &= __ucl_assert(v0 > 0); |
||
168 | r &= __ucl_assert(v1 > 0); |
||
169 | } |
||
170 | } |
||
171 | |||
172 | return r; |
||
173 | } |
||
174 | |||
175 | |||
176 | /*********************************************************************** |
||
177 | // |
||
178 | ************************************************************************/ |
||
179 | |||
180 | UCL_PUBLIC(int) |
||
181 | _ucl_config_check(void) |
||
182 | { |
||
183 | ucl_bool r = 1; |
||
184 | int i; |
||
185 | union { |
||
186 | ucl_uint32 a; |
||
187 | unsigned short b; |
||
188 | ucl_uint32 aa[4]; |
||
189 | unsigned char x[4*sizeof(ucl_align_t)]; |
||
190 | } u; |
||
191 | |||
192 | u.a = 0; u.b = 0; |
||
193 | for (i = 0; i < (int) sizeof(u.x); i++) |
||
194 | u.x[i] = UCL_BYTE(i); |
||
195 | |||
196 | #if defined(ACC_ENDIAN_BIG_ENDIAN) || defined(ACC_ENDIAN_LITTLE_ENDIAN) |
||
197 | if (r == 1) |
||
198 | { |
||
199 | # if defined(ACC_ENDIAN_BIG_ENDIAN) |
||
200 | ucl_uint32 a = u.a >> (8 * sizeof(u.a) - 32); |
||
201 | unsigned short b = u.b >> (8 * sizeof(u.b) - 16); |
||
202 | r &= __ucl_assert(a == UCL_UINT32_C(0x00010203)); |
||
203 | r &= __ucl_assert(b == 0x0001); |
||
204 | # endif |
||
205 | # if defined(ACC_ENDIAN_LITTLE_ENDIAN) |
||
206 | ucl_uint32 a = (ucl_uint32) (u.a & UCL_UINT32_C(0xffffffff)); |
||
207 | unsigned short b = (unsigned short) (u.b & 0xffff); |
||
208 | r &= __ucl_assert(a == UCL_UINT32_C(0x03020100)); |
||
209 | r &= __ucl_assert(b == 0x0100); |
||
210 | # endif |
||
211 | } |
||
212 | #endif |
||
213 | |||
214 | /* check that unaligned memory access works as expected */ |
||
215 | #if defined(UA_GET2) || defined(UA_SET2) |
||
216 | if (r == 1) |
||
217 | { |
||
218 | unsigned short b[4]; |
||
219 | for (i = 0; i < 4; i++) |
||
220 | b[i] = UA_GET2(&u.x[i]); |
||
221 | # if defined(ACC_ENDIAN_LITTLE_ENDIAN) |
||
222 | r &= __ucl_assert(b[0] == 0x0100); |
||
223 | r &= __ucl_assert(b[1] == 0x0201); |
||
224 | r &= __ucl_assert(b[2] == 0x0302); |
||
225 | r &= __ucl_assert(b[3] == 0x0403); |
||
226 | # endif |
||
227 | # if defined(ACC_ENDIAN_BIG_ENDIAN) |
||
228 | r &= __ucl_assert(b[0] == 0x0001); |
||
229 | r &= __ucl_assert(b[1] == 0x0102); |
||
230 | r &= __ucl_assert(b[2] == 0x0203); |
||
231 | r &= __ucl_assert(b[3] == 0x0304); |
||
232 | # endif |
||
233 | } |
||
234 | #endif |
||
235 | |||
236 | #if defined(UA_GET4) || defined(UA_SET4) |
||
237 | if (r == 1) |
||
238 | { |
||
239 | ucl_uint32 a[4]; |
||
240 | for (i = 0; i < 4; i++) |
||
241 | a[i] = UA_GET4(&u.x[i]); |
||
242 | # if defined(ACC_ENDIAN_LITTLE_ENDIAN) |
||
243 | r &= __ucl_assert(a[0] == UCL_UINT32_C(0x03020100)); |
||
244 | r &= __ucl_assert(a[1] == UCL_UINT32_C(0x04030201)); |
||
245 | r &= __ucl_assert(a[2] == UCL_UINT32_C(0x05040302)); |
||
246 | r &= __ucl_assert(a[3] == UCL_UINT32_C(0x06050403)); |
||
247 | # endif |
||
248 | # if defined(ACC_ENDIAN_BIG_ENDIAN) |
||
249 | r &= __ucl_assert(a[0] == UCL_UINT32_C(0x00010203)); |
||
250 | r &= __ucl_assert(a[1] == UCL_UINT32_C(0x01020304)); |
||
251 | r &= __ucl_assert(a[2] == UCL_UINT32_C(0x02030405)); |
||
252 | r &= __ucl_assert(a[3] == UCL_UINT32_C(0x03040506)); |
||
253 | # endif |
||
254 | } |
||
255 | #endif |
||
256 | |||
257 | /* check the ucl_adler32() function */ |
||
258 | if (r == 1) |
||
259 | { |
||
260 | ucl_uint32 adler; |
||
261 | adler = ucl_adler32(0, NULL, 0); |
||
262 | adler = ucl_adler32(adler, ucl_copyright(), 195); |
||
263 | r &= __ucl_assert(adler == UCL_UINT32_C(0x52ca3a75)); |
||
264 | } |
||
265 | |||
266 | /* check for the gcc schedule-insns optimization bug */ |
||
267 | if (r == 1) |
||
268 | { |
||
269 | r &= __ucl_assert(!schedule_insns_bug()); |
||
270 | } |
||
271 | |||
272 | /* check for the gcc strength-reduce optimization bug */ |
||
273 | if (r == 1) |
||
274 | { |
||
275 | static int x[3]; |
||
276 | static unsigned xn = 3; |
||
277 | register unsigned j; |
||
278 | |||
279 | for (j = 0; j < xn; j++) |
||
280 | x[j] = (int)j - 3; |
||
281 | r &= __ucl_assert(!strength_reduce_bug(x)); |
||
282 | } |
||
283 | |||
284 | /* now for the low-level pointer checks */ |
||
285 | if (r == 1) |
||
286 | { |
||
287 | r &= ptr_check(); |
||
288 | } |
||
289 | |||
290 | ACC_UNUSED(u); |
||
291 | return r == 1 ? UCL_E_OK : UCL_E_ERROR; |
||
292 | } |
||
293 | |||
294 | |||
295 | static ucl_bool schedule_insns_bug(void) |
||
296 | { |
||
297 | #if defined(__UCL_CHECKER) |
||
298 | /* for some reason checker complains about uninitialized memory access */ |
||
299 | return 0; |
||
300 | #else |
||
301 | const int clone[] = {1, 2, 0}; |
||
302 | const int *q; |
||
303 | q = clone; |
||
304 | return (*q) ? 0 : 1; |
||
305 | #endif |
||
306 | } |
||
307 | |||
308 | |||
309 | static ucl_bool strength_reduce_bug(int *x) |
||
310 | { |
||
311 | #if 1 && (ACC_CC_DMC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) |
||
312 | return 0; |
||
313 | #else |
||
314 | return x[0] != -3 || x[1] != -2 || x[2] != -1; |
||
315 | #endif |
||
316 | } |
||
317 | |||
318 | |||
319 | /*********************************************************************** |
||
320 | // |
||
321 | ************************************************************************/ |
||
322 | |||
323 | int __ucl_init_done = 0; |
||
324 | |||
325 | UCL_PUBLIC(int) |
||
326 | __ucl_init2(ucl_uint32 v, int s1, int s2, int s3, int s4, int s5, |
||
327 | int s6, int s7, int s8, int s9) |
||
328 | { |
||
329 | int r; |
||
330 | |||
331 | #if (ACC_CC_MSC && ((_MSC_VER) < 700)) |
||
332 | #else |
||
333 | #include "acc/acc_chk.ch" |
||
334 | #undef ACCCHK_ASSERT |
||
335 | #endif |
||
336 | |||
337 | __ucl_init_done = 1; |
||
338 | |||
339 | if (v == 0) |
||
340 | return UCL_E_ERROR; |
||
341 | |||
342 | r = (s1 == -1 || s1 == (int) sizeof(short)) && |
||
343 | (s2 == -1 || s2 == (int) sizeof(int)) && |
||
344 | (s3 == -1 || s3 == (int) sizeof(long)) && |
||
345 | (s4 == -1 || s4 == (int) sizeof(ucl_uint32)) && |
||
346 | (s5 == -1 || s5 == (int) sizeof(ucl_uint)) && |
||
347 | (s6 == -1 || s6 > 0) && |
||
348 | (s7 == -1 || s7 == (int) sizeof(char *)) && |
||
349 | (s8 == -1 || s8 == (int) sizeof(ucl_voidp)) && |
||
350 | (s9 == -1 || s9 == (int) sizeof(ucl_compress_t)); |
||
351 | if (!r) |
||
352 | return UCL_E_ERROR; |
||
353 | |||
354 | r = _ucl_config_check(); |
||
355 | if (r != UCL_E_OK) |
||
356 | return r; |
||
357 | |||
358 | return r; |
||
359 | } |
||
360 | |||
361 | |||
362 | #include "ucl_dll.ch" |
||
363 | |||
364 | |||
365 | /* |
||
366 | vi:ts=4:et |
||
367 | */ |