1 /* ucl_init.c -- initialization of the UCL library
3 This file is part of the UCL data compression library.
5 Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
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.
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.
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.
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/ucl/
35 # define IS_SIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) < 0)
36 # define IS_UNSIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) > 0)
38 # define IS_SIGNED(type) (((type) (-1)) < ((type) 0))
39 # define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0))
43 /***********************************************************************
44 // Runtime check of the assumptions about the size of builtin types,
45 // memory model, byte order and other low-level constructs.
47 // We are really paranoid here - UCL should either fail (or crash)
48 // at startup or not at all.
50 // Because of inlining much of these functions evaluates to nothing.
51 ************************************************************************/
53 static ucl_bool
schedule_insns_bug(void); /* avoid inlining */
54 static ucl_bool
strength_reduce_bug(int *); /* avoid inlining */
57 #if 0 || defined(UCL_DEBUG)
58 static ucl_bool
__ucl_assert_fail(const char *s
, unsigned line
)
60 #if defined(__palmos__)
61 printf("UCL assertion failed in line %u: '%s'\n",line
,s
);
63 fprintf(stderr
,"UCL assertion failed in line %u: '%s'\n",line
,s
);
67 # define __ucl_assert(x) ((x) ? 1 : __ucl_assert_fail(#x,__LINE__))
69 # define __ucl_assert(x) ((x) ? 1 : 0)
73 /***********************************************************************
74 // The next two functions should get completely optimized out of existance.
75 // Some assertions are redundant - but included for clarity.
76 ************************************************************************/
78 static ucl_bool
basic_integral_check(void)
84 r
&= __ucl_assert(CHAR_BIT
== 8);
85 r
&= __ucl_assert(sizeof(char) == 1);
86 r
&= __ucl_assert(sizeof(short) >= 2);
87 r
&= __ucl_assert(sizeof(long) >= 4);
88 r
&= __ucl_assert(sizeof(int) >= sizeof(short));
89 r
&= __ucl_assert(sizeof(long) >= sizeof(int));
91 r
&= __ucl_assert(sizeof(ucl_uint32
) >= 4);
92 r
&= __ucl_assert(sizeof(ucl_uint32
) >= sizeof(unsigned));
93 #if defined(__UCL_STRICT_16BIT)
94 r
&= __ucl_assert(sizeof(ucl_uint
) == 2);
96 r
&= __ucl_assert(sizeof(ucl_uint
) >= 4);
97 r
&= __ucl_assert(sizeof(ucl_uint
) >= sizeof(unsigned));
100 #if defined(SIZEOF_UNSIGNED)
101 r
&= __ucl_assert(SIZEOF_UNSIGNED
== sizeof(unsigned));
103 #if defined(SIZEOF_UNSIGNED_LONG)
104 r
&= __ucl_assert(SIZEOF_UNSIGNED_LONG
== sizeof(unsigned long));
106 #if defined(SIZEOF_UNSIGNED_SHORT)
107 r
&= __ucl_assert(SIZEOF_UNSIGNED_SHORT
== sizeof(unsigned short));
109 #if !defined(__UCL_IN_MINIUCL)
110 #if defined(SIZEOF_SIZE_T)
111 r
&= __ucl_assert(SIZEOF_SIZE_T
== sizeof(size_t));
115 /* assert the signedness of our integral types */
116 sanity
= IS_UNSIGNED(unsigned short) && IS_UNSIGNED(unsigned) &&
117 IS_UNSIGNED(unsigned long) &&
118 IS_SIGNED(short) && IS_SIGNED(int) && IS_SIGNED(long);
121 r
&= __ucl_assert(IS_UNSIGNED(ucl_uint32
));
122 r
&= __ucl_assert(IS_UNSIGNED(ucl_uint
));
123 r
&= __ucl_assert(IS_SIGNED(ucl_int32
));
124 r
&= __ucl_assert(IS_SIGNED(ucl_int
));
126 r
&= __ucl_assert(INT_MAX
== UCL_STYPE_MAX(sizeof(int)));
127 r
&= __ucl_assert(UINT_MAX
== UCL_UTYPE_MAX(sizeof(unsigned)));
128 r
&= __ucl_assert(LONG_MAX
== UCL_STYPE_MAX(sizeof(long)));
129 r
&= __ucl_assert(ULONG_MAX
== UCL_UTYPE_MAX(sizeof(unsigned long)));
130 r
&= __ucl_assert(SHRT_MAX
== UCL_STYPE_MAX(sizeof(short)));
131 r
&= __ucl_assert(USHRT_MAX
== UCL_UTYPE_MAX(sizeof(unsigned short)));
132 r
&= __ucl_assert(UCL_UINT32_MAX
== UCL_UTYPE_MAX(sizeof(ucl_uint32
)));
133 r
&= __ucl_assert(UCL_UINT_MAX
== UCL_UTYPE_MAX(sizeof(ucl_uint
)));
134 #if !defined(__UCL_IN_MINIUCL)
135 r
&= __ucl_assert(SIZE_T_MAX
== UCL_UTYPE_MAX(sizeof(size_t)));
143 static ucl_bool
basic_ptr_check(void)
148 r
&= __ucl_assert(sizeof(char *) >= sizeof(int));
149 r
&= __ucl_assert(sizeof(ucl_byte
*) >= sizeof(char *));
151 r
&= __ucl_assert(sizeof(ucl_voidp
) == sizeof(ucl_byte
*));
152 r
&= __ucl_assert(sizeof(ucl_voidp
) == sizeof(ucl_voidpp
));
153 r
&= __ucl_assert(sizeof(ucl_voidp
) == sizeof(ucl_bytepp
));
154 r
&= __ucl_assert(sizeof(ucl_voidp
) >= sizeof(ucl_uint
));
156 r
&= __ucl_assert(sizeof(ucl_ptr_t
) == sizeof(ucl_voidp
));
157 r
&= __ucl_assert(sizeof(ucl_ptr_t
) >= sizeof(ucl_uint
));
159 r
&= __ucl_assert(sizeof(ucl_ptrdiff_t
) >= 4);
160 r
&= __ucl_assert(sizeof(ucl_ptrdiff_t
) >= sizeof(ptrdiff_t));
162 #if defined(SIZEOF_CHAR_P)
163 r
&= __ucl_assert(SIZEOF_CHAR_P
== sizeof(char *));
165 #if defined(SIZEOF_PTRDIFF_T)
166 r
&= __ucl_assert(SIZEOF_PTRDIFF_T
== sizeof(ptrdiff_t));
169 /* assert the signedness of our integral types */
170 sanity
= IS_UNSIGNED(unsigned short) && IS_UNSIGNED(unsigned) &&
171 IS_UNSIGNED(unsigned long) &&
172 IS_SIGNED(short) && IS_SIGNED(int) && IS_SIGNED(long);
175 r
&= __ucl_assert(IS_UNSIGNED(ucl_ptr_t
));
176 r
&= __ucl_assert(IS_SIGNED(ucl_ptrdiff_t
));
177 r
&= __ucl_assert(IS_SIGNED(ucl_sptr_t
));
184 /***********************************************************************
186 ************************************************************************/
188 static ucl_bool
ptr_check(void)
192 char _wrkmem
[10 * sizeof(ucl_byte
*) + sizeof(ucl_align_t
)];
195 unsigned char x
[4 * sizeof(ucl_align_t
)];
200 for (i
= 0; i
< (int) sizeof(x
); i
++)
203 wrkmem
= UCL_PTR_ALIGN_UP((ucl_byte
*)_wrkmem
,sizeof(ucl_align_t
));
206 dict
= (ucl_bytepp
) wrkmem
;
208 /* Avoid a compiler warning on architectures that
209 * do not allow unaligned access. */
210 u
.a_ucl_bytep
= wrkmem
; dict
= u
.a_ucl_bytepp
;
213 d
= (long) ((const ucl_bytep
) dict
- (const ucl_bytep
) _wrkmem
);
214 r
&= __ucl_assert(d
>= 0);
215 r
&= __ucl_assert(d
< (long) sizeof(ucl_align_t
));
217 memset(&a
,0xff,sizeof(a
));
218 r
&= __ucl_assert(a
.a_ushort
== USHRT_MAX
);
219 r
&= __ucl_assert(a
.a_uint
== UINT_MAX
);
220 r
&= __ucl_assert(a
.a_ulong
== ULONG_MAX
);
221 r
&= __ucl_assert(a
.a_ucl_uint
== UCL_UINT_MAX
);
223 /* sanity check of the memory model */
226 for (i
= 0; i
< 8; i
++)
227 r
&= __ucl_assert((const ucl_voidp
) (&dict
[i
]) == (const ucl_voidp
) (&wrkmem
[i
* sizeof(ucl_byte
*)]));
230 /* check BZERO8_PTR and that NULL == 0 */
231 memset(&a
,0,sizeof(a
));
232 r
&= __ucl_assert(a
.a_char_p
== NULL
);
233 r
&= __ucl_assert(a
.a_ucl_bytep
== NULL
);
234 r
&= __ucl_assert(NULL
== (void*)0);
237 for (i
= 0; i
< 10; i
++)
239 BZERO8_PTR(dict
+1,sizeof(dict
[0]),8);
240 r
&= __ucl_assert(dict
[0] == wrkmem
);
241 for (i
= 1; i
< 9; i
++)
242 r
&= __ucl_assert(dict
[i
] == NULL
);
243 r
&= __ucl_assert(dict
[9] == wrkmem
);
246 /* check that the pointer constructs work as expected */
250 const unsigned n
= (unsigned) sizeof(ucl_uint32
);
254 k
+= __ucl_align_gap(&x
[k
],n
);
255 p0
= (ucl_bytep
) &x
[k
];
256 #if defined(PTR_LINEAR)
257 r
&= __ucl_assert((PTR_LINEAR(p0
) & (n
-1)) == 0);
259 r
&= __ucl_assert(n
== 4);
260 r
&= __ucl_assert(PTR_ALIGNED_4(p0
));
263 r
&= __ucl_assert(k
>= 1);
264 p1
= (ucl_bytep
) &x
[1];
265 r
&= __ucl_assert(PTR_GE(p0
,p1
));
267 r
&= __ucl_assert(k
< 1+n
);
268 p1
= (ucl_bytep
) &x
[1+n
];
269 r
&= __ucl_assert(PTR_LT(p0
,p1
));
271 /* now check that aligned memory access doesn't core dump */
276 v0
= * (ucl_uint32
*) &x
[k
];
277 v1
= * (ucl_uint32
*) &x
[k
+n
];
279 /* Avoid compiler warnings on architectures that
280 * do not allow unaligned access. */
282 v0
= *u
.a_ucl_uint32_p
;
283 u
.a_uchar_p
= &x
[k
+n
];
284 v1
= *u
.a_ucl_uint32_p
;
286 r
&= __ucl_assert(v0
> 0);
287 r
&= __ucl_assert(v1
> 0);
295 /***********************************************************************
297 ************************************************************************/
300 _ucl_config_check(void)
308 unsigned char x
[4*sizeof(ucl_align_t
)];
312 /* paranoia - the following is guaranteed by definition anyway */
313 r
&= __ucl_assert((const void *)&u
== (const void *)&u
.a
);
314 r
&= __ucl_assert((const void *)&u
== (const void *)&u
.b
);
315 r
&= __ucl_assert((const void *)&u
== (const void *)&u
.x
[0]);
316 r
&= __ucl_assert((const void *)&u
== (const void *)&u
.aa
[0]);
319 r
&= basic_integral_check();
320 r
&= basic_ptr_check();
325 for (i
= 0; i
< (int) sizeof(u
.x
); i
++)
326 u
.x
[i
] = UCL_BYTE(i
);
329 /* check if the compiler correctly casts signed to unsigned */
330 r
&= __ucl_assert( (int) (unsigned char) ((char) -1) == 255);
333 /* check UCL_BYTE_ORDER */
334 #if defined(UCL_BYTE_ORDER)
337 # if (UCL_BYTE_ORDER == UCL_LITTLE_ENDIAN)
338 ucl_uint32 a
= (ucl_uint32
) (u
.a
& UCL_UINT32_C(0xffffffff));
339 unsigned short b
= (unsigned short) (u
.b
& 0xffff);
340 r
&= __ucl_assert(a
== UCL_UINT32_C(0x03020100));
341 r
&= __ucl_assert(b
== 0x0100);
342 # elif (UCL_BYTE_ORDER == UCL_BIG_ENDIAN)
343 ucl_uint32 a
= u
.a
>> (8 * sizeof(u
.a
) - 32);
344 unsigned short b
= u
.b
>> (8 * sizeof(u
.b
) - 16);
345 r
&= __ucl_assert(a
== UCL_UINT32_C(0x00010203));
346 r
&= __ucl_assert(b
== 0x0001);
348 # error "invalid UCL_BYTE_ORDER"
353 /* check that unaligned memory access works as expected */
354 #if defined(UCL_UNALIGNED_OK_2)
355 r
&= __ucl_assert(sizeof(short) == 2);
360 for (i
= 0; i
< 4; i
++)
361 b
[i
] = * (const unsigned short *) &u
.x
[i
];
363 # if (UCL_BYTE_ORDER == UCL_LITTLE_ENDIAN)
364 r
&= __ucl_assert(b
[0] == 0x0100);
365 r
&= __ucl_assert(b
[1] == 0x0201);
366 r
&= __ucl_assert(b
[2] == 0x0302);
367 r
&= __ucl_assert(b
[3] == 0x0403);
368 # elif (UCL_BYTE_ORDER == UCL_BIG_ENDIAN)
369 r
&= __ucl_assert(b
[0] == 0x0001);
370 r
&= __ucl_assert(b
[1] == 0x0102);
371 r
&= __ucl_assert(b
[2] == 0x0203);
372 r
&= __ucl_assert(b
[3] == 0x0304);
377 #if defined(UCL_UNALIGNED_OK_4)
378 r
&= __ucl_assert(sizeof(ucl_uint32
) == 4);
383 for (i
= 0; i
< 4; i
++)
384 a
[i
] = * (const ucl_uint32
*) &u
.x
[i
];
386 # if (UCL_BYTE_ORDER == UCL_LITTLE_ENDIAN)
387 r
&= __ucl_assert(a
[0] == UCL_UINT32_C(0x03020100));
388 r
&= __ucl_assert(a
[1] == UCL_UINT32_C(0x04030201));
389 r
&= __ucl_assert(a
[2] == UCL_UINT32_C(0x05040302));
390 r
&= __ucl_assert(a
[3] == UCL_UINT32_C(0x06050403));
391 # elif (UCL_BYTE_ORDER == UCL_BIG_ENDIAN)
392 r
&= __ucl_assert(a
[0] == UCL_UINT32_C(0x00010203));
393 r
&= __ucl_assert(a
[1] == UCL_UINT32_C(0x01020304));
394 r
&= __ucl_assert(a
[2] == UCL_UINT32_C(0x02030405));
395 r
&= __ucl_assert(a
[3] == UCL_UINT32_C(0x03040506));
400 #if defined(UCL_ALIGNED_OK_4)
401 r
&= __ucl_assert(sizeof(ucl_uint32
) == 4);
404 /* check the ucl_adler32() function */
408 adler
= ucl_adler32(0, NULL
, 0);
409 adler
= ucl_adler32(adler
, ucl_copyright(), 186);
410 r
&= __ucl_assert(adler
== UCL_UINT32_C(0x47fb39fc));
413 /* check for the gcc schedule-insns optimization bug */
416 r
&= __ucl_assert(!schedule_insns_bug());
419 /* check for the gcc strength-reduce optimization bug */
423 static unsigned xn
= 3;
426 for (j
= 0; j
< xn
; j
++)
428 r
&= __ucl_assert(!strength_reduce_bug(x
));
431 /* now for the low-level pointer checks */
437 return r
== 1 ? UCL_E_OK
: UCL_E_ERROR
;
441 static ucl_bool
schedule_insns_bug(void)
443 #if defined(__UCL_CHECKER)
444 /* for some reason checker complains about uninitialized memory access */
447 const int clone
[] = {1, 2, 0};
455 static ucl_bool
strength_reduce_bug(int *x
)
457 return x
[0] != -3 || x
[1] != -2 || x
[2] != -1;
461 /***********************************************************************
463 ************************************************************************/
465 int __ucl_init_done
= 0;
468 __ucl_init2(ucl_uint32 v
, int s1
, int s2
, int s3
, int s4
, int s5
,
469 int s6
, int s7
, int s8
, int s9
)
478 r
= (s1
== -1 || s1
== (int) sizeof(short)) &&
479 (s2
== -1 || s2
== (int) sizeof(int)) &&
480 (s3
== -1 || s3
== (int) sizeof(long)) &&
481 (s4
== -1 || s4
== (int) sizeof(ucl_uint32
)) &&
482 (s5
== -1 || s5
== (int) sizeof(ucl_uint
)) &&
483 (s6
== -1 || s6
> 0) &&
484 (s7
== -1 || s7
== (int) sizeof(char *)) &&
485 (s8
== -1 || s8
== (int) sizeof(ucl_voidp
)) &&
486 (s9
== -1 || s9
== (int) sizeof(ucl_compress_t
));
490 r
= _ucl_config_check();