]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_selftest.c
import 12.2.13 release
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.5.2 / src-separate / duk_selftest.c
1 /*
2 * Self tests to ensure execution environment is sane. Intended to catch
3 * compiler/platform problems which cannot be detected at compile time.
4 */
5
6 #include "duk_internal.h"
7
8 #if defined(DUK_USE_SELF_TESTS)
9
10 /*
11 * Unions and structs for self tests
12 */
13
14 typedef union {
15 double d;
16 duk_uint8_t c[8];
17 } duk__test_double_union;
18
19 #define DUK__DBLUNION_CMP_TRUE(a,b) do { \
20 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
21 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
22 } \
23 } while (0)
24
25 #define DUK__DBLUNION_CMP_FALSE(a,b) do { \
26 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
27 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
28 } \
29 } while (0)
30
31 typedef union {
32 duk_uint32_t i;
33 duk_uint8_t c[8];
34 } duk__test_u32_union;
35
36 /*
37 * Various sanity checks for typing
38 */
39
40 DUK_LOCAL void duk__selftest_types(void) {
41 if (!(sizeof(duk_int8_t) == 1 &&
42 sizeof(duk_uint8_t) == 1 &&
43 sizeof(duk_int16_t) == 2 &&
44 sizeof(duk_uint16_t) == 2 &&
45 sizeof(duk_int32_t) == 4 &&
46 sizeof(duk_uint32_t) == 4)) {
47 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size");
48 }
49 #if defined(DUK_USE_64BIT_OPS)
50 if (!(sizeof(duk_int64_t) == 8 &&
51 sizeof(duk_uint64_t) == 8)) {
52 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size");
53 }
54 #endif
55
56 if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
57 /* Some internal code now assumes that all duk_uint_t values
58 * can be expressed with a duk_size_t.
59 */
60 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t");
61 }
62 if (!(sizeof(duk_int_t) >= 4)) {
63 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits");
64 }
65 }
66
67 /*
68 * Packed tval sanity
69 */
70
71 DUK_LOCAL void duk__selftest_packed_tval(void) {
72 #if defined(DUK_USE_PACKED_TVAL)
73 if (sizeof(void *) > 4) {
74 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4");
75 }
76 #endif
77 }
78
79 /*
80 * Two's complement arithmetic.
81 */
82
83 DUK_LOCAL void duk__selftest_twos_complement(void) {
84 volatile int test;
85 test = -1;
86
87 /* Note that byte order doesn't affect this test: all bytes in
88 * 'test' will be 0xFF for two's complement.
89 */
90 if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
91 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
92 }
93 }
94
95 /*
96 * Byte order. Important to self check, because on some exotic platforms
97 * there is no actual detection but rather assumption based on platform
98 * defines.
99 */
100
101 DUK_LOCAL void duk__selftest_byte_order(void) {
102 duk__test_u32_union u1;
103 duk__test_double_union u2;
104
105 /*
106 * >>> struct.pack('>d', 102030405060).encode('hex')
107 * '4237c17c6dc40000'
108 */
109 #if defined(DUK_USE_INTEGER_LE)
110 u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
111 #elif defined(DUK_USE_INTEGER_ME)
112 #error integer mixed endian not supported now
113 #elif defined(DUK_USE_INTEGER_BE)
114 u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
115 #else
116 #error unknown integer endianness
117 #endif
118
119 #if defined(DUK_USE_DOUBLE_LE)
120 u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
121 u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
122 #elif defined(DUK_USE_DOUBLE_ME)
123 u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
124 u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
125 #elif defined(DUK_USE_DOUBLE_BE)
126 u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
127 u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
128 #else
129 #error unknown double endianness
130 #endif
131
132 if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
133 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
134 }
135
136 if (u2.d != (double) 102030405060.0) {
137 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
138 }
139 }
140
141 /*
142 * DUK_BSWAP macros
143 */
144
145 DUK_LOCAL void duk__selftest_bswap_macros(void) {
146 duk_uint32_t x32;
147 duk_uint16_t x16;
148 duk_double_union du;
149 duk_double_t du_diff;
150
151 x16 = 0xbeefUL;
152 x16 = DUK_BSWAP16(x16);
153 if (x16 != (duk_uint16_t) 0xefbeUL) {
154 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16");
155 }
156
157 x32 = 0xdeadbeefUL;
158 x32 = DUK_BSWAP32(x32);
159 if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
160 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32");
161 }
162
163 /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
164 * (2.008366013071895,)
165 */
166
167 du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
168 du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
169 DUK_DBLUNION_DOUBLE_NTOH(&du);
170 du_diff = du.d - 2.008366013071895;
171 #if 0
172 DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
173 #endif
174 if (du_diff > 1e-15) {
175 /* Allow very small lenience because some compilers won't parse
176 * exact IEEE double constants (happened in matrix testing with
177 * Linux gcc-4.8 -m32 at least).
178 */
179 #if 0
180 DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
181 (unsigned int) du.uc[0], (unsigned int) du.uc[1],
182 (unsigned int) du.uc[2], (unsigned int) du.uc[3],
183 (unsigned int) du.uc[4], (unsigned int) du.uc[5],
184 (unsigned int) du.uc[6], (unsigned int) du.uc[7]);
185 #endif
186 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH");
187 }
188 }
189
190 /*
191 * Basic double / byte union memory layout.
192 */
193
194 DUK_LOCAL void duk__selftest_double_union_size(void) {
195 if (sizeof(duk__test_double_union) != 8) {
196 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
197 }
198 }
199
200 /*
201 * Union aliasing, see misc/clang_aliasing.c.
202 */
203
204 DUK_LOCAL void duk__selftest_double_aliasing(void) {
205 duk__test_double_union a, b;
206
207 /* This testcase fails when Emscripten-generated code runs on Firefox.
208 * It's not an issue because the failure should only affect packed
209 * duk_tval representation, which is not used with Emscripten.
210 */
211 #if !defined(DUK_USE_PACKED_TVAL)
212 DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
213 return;
214 #endif
215
216 /* Test signaling NaN and alias assignment in all endianness combinations.
217 */
218
219 /* little endian */
220 a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
221 a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
222 b = a;
223 DUK__DBLUNION_CMP_TRUE(&a, &b);
224
225 /* big endian */
226 a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
227 a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
228 b = a;
229 DUK__DBLUNION_CMP_TRUE(&a, &b);
230
231 /* mixed endian */
232 a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
233 a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
234 b = a;
235 DUK__DBLUNION_CMP_TRUE(&a, &b);
236 }
237
238 /*
239 * Zero sign, see misc/tcc_zerosign2.c.
240 */
241
242 DUK_LOCAL void duk__selftest_double_zero_sign(void) {
243 duk__test_double_union a, b;
244
245 a.d = 0.0;
246 b.d = -a.d;
247 DUK__DBLUNION_CMP_FALSE(&a, &b);
248 }
249
250 /*
251 * Struct size/alignment if platform requires it
252 *
253 * There are some compiler specific struct padding pragmas etc in use, this
254 * selftest ensures they're correctly detected and used.
255 */
256
257 DUK_LOCAL void duk__selftest_struct_align(void) {
258 #if (DUK_USE_ALIGN_BY == 4)
259 if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
260 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
261 }
262 #elif (DUK_USE_ALIGN_BY == 8)
263 if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
264 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
265 }
266 #elif (DUK_USE_ALIGN_BY == 1)
267 /* no check */
268 #else
269 #error invalid DUK_USE_ALIGN_BY
270 #endif
271 }
272
273 /*
274 * 64-bit arithmetic
275 *
276 * There are some platforms/compilers where 64-bit types are available
277 * but don't work correctly. Test for known cases.
278 */
279
280 DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
281 #if defined(DUK_USE_64BIT_OPS)
282 volatile duk_int64_t i;
283 volatile duk_double_t d;
284
285 /* Catch a double-to-int64 cast issue encountered in practice. */
286 d = 2147483648.0;
287 i = (duk_int64_t) d;
288 if (i != 0x80000000LL) {
289 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed");
290 }
291 #else
292 /* nop */
293 #endif
294 }
295
296 /*
297 * Casting
298 */
299
300 DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
301 /*
302 * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
303 */
304
305 duk_double_t d1, d2;
306 duk_small_uint_t u;
307
308 duk_double_t d1v, d2v;
309 duk_small_uint_t uv;
310
311 /* Test without volatiles */
312
313 d1 = 1.0;
314 u = (duk_small_uint_t) d1;
315 d2 = (duk_double_t) u;
316
317 if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
318 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
319 }
320
321 /* Same test with volatiles */
322
323 d1v = 1.0;
324 uv = (duk_small_uint_t) d1v;
325 d2v = (duk_double_t) uv;
326
327 if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
328 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
329 }
330 }
331
332 DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
333 /*
334 * This test fails on an exotic ARM target; double-to-uint
335 * cast is incorrectly clamped to -signed- int highest value.
336 *
337 * https://github.com/svaarala/duktape/issues/336
338 */
339
340 duk_double_t dv;
341 duk_uint32_t uv;
342
343 dv = 3735928559.0; /* 0xdeadbeef in decimal */
344 uv = (duk_uint32_t) dv;
345
346 if (uv != 0xdeadbeefUL) {
347 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed");
348 }
349 }
350
351 /*
352 * Self test main
353 */
354
355 DUK_INTERNAL void duk_selftest_run_tests(void) {
356 duk__selftest_types();
357 duk__selftest_packed_tval();
358 duk__selftest_twos_complement();
359 duk__selftest_byte_order();
360 duk__selftest_bswap_macros();
361 duk__selftest_double_union_size();
362 duk__selftest_double_aliasing();
363 duk__selftest_double_zero_sign();
364 duk__selftest_struct_align();
365 duk__selftest_64bit_arithmetic();
366 duk__selftest_cast_double_to_small_uint();
367 duk__selftest_cast_double_to_uint32();
368 }
369
370 #undef DUK__DBLUNION_CMP_TRUE
371 #undef DUK__DBLUNION_CMP_FALSE
372
373 #endif /* DUK_USE_SELF_TESTS */