1 /*
2  * Unit tests for miscellaneous msvcrt functions
3  *
4  * Copyright 2010 Andrew Nguyen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "wine/test.h"
22 #include <errno.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include "msvcrt.h"
26 #include <process.h>
27 
28 static inline float __port_infinity(void)
29 {
30     static const unsigned __inf_bytes = 0x7f800000;
31     return *(const float *)&__inf_bytes;
32 }
33 #ifdef __REACTOS__
34 #undef INFINITY
35 #endif
36 #define INFINITY __port_infinity()
37 
38 static inline float __port_nan(void)
39 {
40     static const unsigned __nan_bytes = 0x7fc00000;
41     return *(const float *)&__nan_bytes;
42 }
43 #ifdef __REACTOS__
44 #undef NAN
45 #endif
46 #define NAN __port_nan()
47 
48 static inline BOOL almost_equal(double d1, double d2) {
49     if(d1-d2>-1e-30 && d1-d2<1e-30)
50         return TRUE;
51     return FALSE;
52 }
53 
54 static int (__cdecl *prand_s)(unsigned int *);
55 static int (__cdecl *pI10_OUTPUT)(long double, int, int, void*);
56 static int (__cdecl *pstrerror_s)(char *, MSVCRT_size_t, int);
57 static int (__cdecl *p_get_doserrno)(int *);
58 static int (__cdecl *p_get_errno)(int *);
59 static int (__cdecl *p_set_doserrno)(int);
60 static int (__cdecl *p_set_errno)(int);
61 static void (__cdecl *p__invalid_parameter)(const wchar_t*,
62         const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
63 static void (__cdecl *p_qsort_s)(void*, MSVCRT_size_t, MSVCRT_size_t,
64         int (__cdecl*)(void*, const void*, const void*), void*);
65 static double (__cdecl *p_atan)(double);
66 static double (__cdecl *p_exp)(double);
67 static double (__cdecl *p_tanh)(double);
68 static void *(__cdecl *p_lfind_s)(const void*, const void*, unsigned int*,
69         size_t, int (__cdecl *)(void*, const void*, const void*), void*);
70 
71 static void init(void)
72 {
73     HMODULE hmod = GetModuleHandleA("msvcrt.dll");
74 
75     prand_s = (void *)GetProcAddress(hmod, "rand_s");
76     pI10_OUTPUT = (void*)GetProcAddress(hmod, "$I10_OUTPUT");
77     pstrerror_s = (void *)GetProcAddress(hmod, "strerror_s");
78     p_get_doserrno = (void *)GetProcAddress(hmod, "_get_doserrno");
79     p_get_errno = (void *)GetProcAddress(hmod, "_get_errno");
80     p_set_doserrno = (void *)GetProcAddress(hmod, "_set_doserrno");
81     p_set_errno = (void *)GetProcAddress(hmod, "_set_errno");
82     p__invalid_parameter = (void *)GetProcAddress(hmod, "_invalid_parameter");
83     p_qsort_s = (void *)GetProcAddress(hmod, "qsort_s");
84     p_atan = (void *)GetProcAddress(hmod, "atan");
85     p_exp = (void *)GetProcAddress(hmod, "exp");
86     p_tanh = (void *)GetProcAddress(hmod, "tanh");
87     p_lfind_s = (void *)GetProcAddress(hmod, "_lfind_s");
88 }
89 
90 static void test_rand_s(void)
91 {
92     int ret;
93     unsigned int rand;
94 
95     if (!prand_s)
96     {
97         win_skip("rand_s is not available\n");
98         return;
99     }
100 
101     errno = EBADF;
102     ret = prand_s(NULL);
103     ok(ret == EINVAL, "Expected rand_s to return EINVAL, got %d\n", ret);
104     ok(errno == EINVAL, "Expected errno to return EINVAL, got %d\n", errno);
105 
106     ret = prand_s(&rand);
107     ok(ret == 0, "Expected rand_s to return 0, got %d\n", ret);
108 }
109 
110 typedef struct _I10_OUTPUT_data {
111     short pos;
112     char sign;
113     BYTE len;
114     char str[100];
115 } I10_OUTPUT_data;
116 
117 typedef struct _I10_OUTPUT_test {
118     long double d;
119     int size;
120     int flags;
121 
122     I10_OUTPUT_data out;
123     int ret;
124     const char *remain;
125 } I10_OUTPUT_test;
126 
127 static const I10_OUTPUT_test I10_OUTPUT_tests[] = {
128     /* arg3 = 0 */
129     { 0.0, 10, 0, {0, ' ', 1, "0"}, 1, "" },
130     { 1.0, 10, 0, {1, ' ', 1, "1"}, 1, "000000009" },
131     { -1.0, 10, 0, {1, '-', 1, "1"}, 1, "000000009" },
132     { 1.23, 10, 0, {1, ' ', 3, "123"}, 1, "0000009" },
133     { 1e13, 10, 0, {14, ' ', 1, "1"}, 1, "000000009" },
134     { 1e30, 30, 0, {31, ' ', 21, "100000000000000001988"}, 1, "" },
135     { 1e-13, 10, 0, {-12, ' ', 1, "1"}, 1, "000000000" },
136     { 0.25, 10, 0, {0, ' ', 2, "25"}, 1, "00000000" },
137     { 1.0000001, 10, 0, {1, ' ', 8, "10000001"}, 1, "00" },
138     /* arg3 = 1 */
139     { 0.0, 10, 1, {0, ' ', 1, "0"}, 1, "" },
140     { 1.0, 10, 1, {1, ' ', 1, "1"}, 1, "0000000009" },
141     { -1.0, 10, 1, {1, '-', 1, "1"}, 1, "0000000009" },
142     { 1.23, 10, 1, {1, ' ', 3, "123"}, 1, "00000009" },
143     { 1e13, 10, 1, {14, ' ', 1, "1"}, 1, "00000000000000000009" },
144     { 1e30, 30, 1, {31, ' ', 21, "100000000000000001988"}, 1, "" },
145     { 1e-13, 10, 1, {0, ' ', 1, "0"}, 1, "" },
146     { 1e-7, 10, 1, {-6, ' ', 1, "1"}, 1, "09" },
147     { 0.25, 10, 1, {0, ' ', 2, "25"}, 1, "00000000" },
148     { 1.0000001, 10, 1, {1, ' ', 8, "10000001"}, 1, "000" },
149     /* too small buffer */
150     { 0.0, 0, 0, {0, ' ', 1, "0"}, 1, "" },
151     { 0.0, 0, 1, {0, ' ', 1, "0"}, 1, "" },
152     { 123.0, 2, 0, {3, ' ', 2, "12"}, 1, "" },
153     { 123.0, 0, 0, {0, ' ', 1, "0"}, 1, "" },
154     { 123.0, 2, 1, {3, ' ', 3, "123"}, 1, "09" },
155     { 0.99, 1, 0, {1, ' ', 1, "1"}, 1, "" },
156     { 1264567.0, 2, 0, {7, ' ', 2, "13"}, 1, "" },
157     { 1264567.0, 2, 1, {7, ' ', 7, "1264567"}, 1, "00" },
158     { 1234567891.0, 2, 1, {10, ' ', 10, "1234567891"}, 1, "09" }
159 };
160 
161 static void test_I10_OUTPUT(void)
162 {
163     I10_OUTPUT_data out;
164     int i, j = sizeof(long double), ret;
165 
166     if(!pI10_OUTPUT) {
167         win_skip("I10_OUTPUT not available\n");
168         return;
169     }
170     if (j != 12)
171         trace("sizeof(long double) = %d on this machine\n", j);
172 
173     for(i=0; i<ARRAY_SIZE(I10_OUTPUT_tests); i++) {
174         memset(out.str, '#', sizeof(out.str));
175 
176         if (sizeof(long double) == 12)
177             ret = pI10_OUTPUT(I10_OUTPUT_tests[i].d, I10_OUTPUT_tests[i].size, I10_OUTPUT_tests[i].flags, &out);
178         else {
179             /* MS' "long double" is an 80 bit FP that takes 12 bytes*/
180             typedef struct { ULONG x80[3]; } uld; /* same calling convention */
181             union { long double ld; uld ld12; } fp80;
182             int (__cdecl *pI10_OUTPUT12)(uld, int, int, void*) = (void*)pI10_OUTPUT;
183             fp80.ld = I10_OUTPUT_tests[i].d;
184             ret = pI10_OUTPUT12(fp80.ld12, I10_OUTPUT_tests[i].size, I10_OUTPUT_tests[i].flags, &out);
185         }
186         ok(ret == I10_OUTPUT_tests[i].ret, "%d: ret = %d\n", i, ret);
187         ok(out.pos == I10_OUTPUT_tests[i].out.pos, "%d: out.pos = %hd\n", i, out.pos);
188         ok(out.sign == I10_OUTPUT_tests[i].out.sign, "%d: out.size = %c\n", i, out.sign);
189         ok(out.len == I10_OUTPUT_tests[i].out.len, "%d: out.len = %d\n", i, (int)out.len);
190         ok(!strcmp(out.str, I10_OUTPUT_tests[i].out.str), "%d: out.str = %s\n", i, out.str);
191 
192         j = strlen(I10_OUTPUT_tests[i].remain);
193         todo_wine_if(j && I10_OUTPUT_tests[i].remain[j-1]=='9')
194             ok(!strncmp(out.str+out.len+1, I10_OUTPUT_tests[i].remain, j),
195                     "%d: &out.str[%d] = %.25s...\n", i, out.len+1, out.str+out.len+1);
196 
197         for(j=out.len+strlen(I10_OUTPUT_tests[i].remain)+1; j<sizeof(out.str); j++)
198             if(out.str[j] != '#')
199                 ok(0, "%d: out.str[%d] = %c (expected \'#\')\n", i, j, out.str[j]);
200     }
201 }
202 
203 static void test_strerror_s(void)
204 {
205     int ret;
206     char buf[256];
207 
208     if (!pstrerror_s)
209     {
210         win_skip("strerror_s is not available\n");
211         return;
212     }
213 
214     errno = EBADF;
215     ret = pstrerror_s(NULL, 0, 0);
216     ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
217     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
218 
219     errno = EBADF;
220     ret = pstrerror_s(NULL, sizeof(buf), 0);
221     ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
222     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
223 
224     memset(buf, 'X', sizeof(buf));
225     errno = EBADF;
226     ret = pstrerror_s(buf, 0, 0);
227     ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
228     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
229     ok(buf[0] == 'X', "Expected output buffer to be untouched\n");
230 
231     memset(buf, 'X', sizeof(buf));
232     ret = pstrerror_s(buf, 1, 0);
233     ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
234     ok(strlen(buf) == 0, "Expected output buffer to be null terminated\n");
235 
236     memset(buf, 'X', sizeof(buf));
237     ret = pstrerror_s(buf, 2, 0);
238     ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
239     ok(strlen(buf) == 1, "Expected output buffer to be truncated\n");
240 
241     memset(buf, 'X', sizeof(buf));
242     ret = pstrerror_s(buf, sizeof(buf), 0);
243     ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
244 
245     memset(buf, 'X', sizeof(buf));
246     ret = pstrerror_s(buf, sizeof(buf), -1);
247     ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
248 }
249 
250 static void test__get_doserrno(void)
251 {
252     int ret, out;
253 
254     if (!p_get_doserrno)
255     {
256         win_skip("_get_doserrno is not available\n");
257         return;
258     }
259 
260     _doserrno = ERROR_INVALID_CMM;
261     errno = EBADF;
262     ret = p_get_doserrno(NULL);
263     ok(ret == EINVAL, "Expected _get_doserrno to return EINVAL, got %d\n", ret);
264     ok(_doserrno == ERROR_INVALID_CMM, "Expected _doserrno to be ERROR_INVALID_CMM, got %d\n", _doserrno);
265     ok(errno == EBADF, "Expected errno to be EBADF, got %d\n", errno);
266 
267     _doserrno = ERROR_INVALID_CMM;
268     errno = EBADF;
269     out = 0xdeadbeef;
270     ret = p_get_doserrno(&out);
271     ok(ret == 0, "Expected _get_doserrno to return 0, got %d\n", ret);
272     ok(out == ERROR_INVALID_CMM, "Expected output variable to be ERROR_INVALID_CMM, got %d\n", out);
273 }
274 
275 static void test__get_errno(void)
276 {
277     int ret, out;
278 
279     if (!p_get_errno)
280     {
281         win_skip("_get_errno is not available\n");
282         return;
283     }
284 
285     errno = EBADF;
286     ret = p_get_errno(NULL);
287     ok(ret == EINVAL, "Expected _get_errno to return EINVAL, got %d\n", ret);
288     ok(errno == EBADF, "Expected errno to be EBADF, got %d\n", errno);
289 
290     errno = EBADF;
291     out = 0xdeadbeef;
292     ret = p_get_errno(&out);
293     ok(ret == 0, "Expected _get_errno to return 0, got %d\n", ret);
294     ok(out == EBADF, "Expected output variable to be EBADF, got %d\n", out);
295 }
296 
297 static void test__set_doserrno(void)
298 {
299     int ret;
300 
301     if (!p_set_doserrno)
302     {
303         win_skip("_set_doserrno is not available\n");
304         return;
305     }
306 
307     _doserrno = ERROR_INVALID_CMM;
308     ret = p_set_doserrno(ERROR_FILE_NOT_FOUND);
309     ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
310     ok(_doserrno == ERROR_FILE_NOT_FOUND,
311        "Expected _doserrno to be ERROR_FILE_NOT_FOUND, got %d\n", _doserrno);
312 
313     _doserrno = ERROR_INVALID_CMM;
314     ret = p_set_doserrno(-1);
315     ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
316     ok(_doserrno == -1,
317        "Expected _doserrno to be -1, got %d\n", _doserrno);
318 
319     _doserrno = ERROR_INVALID_CMM;
320     ret = p_set_doserrno(0xdeadbeef);
321     ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
322     ok(_doserrno == 0xdeadbeef,
323        "Expected _doserrno to be 0xdeadbeef, got %d\n", _doserrno);
324 }
325 
326 static void test__set_errno(void)
327 {
328     int ret;
329 
330     if (!p_set_errno)
331     {
332         win_skip("_set_errno is not available\n");
333         return;
334     }
335 
336     errno = EBADF;
337     ret = p_set_errno(EINVAL);
338     ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
339     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
340 
341     errno = EBADF;
342     ret = p_set_errno(-1);
343     ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
344     ok(errno == -1, "Expected errno to be -1, got %d\n", errno);
345 
346     errno = EBADF;
347     ret = p_set_errno(0xdeadbeef);
348     ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
349     ok(errno == 0xdeadbeef, "Expected errno to be 0xdeadbeef, got %d\n", errno);
350 }
351 
352 static void test__popen_child(void)
353 {
354     /* don't execute any tests here */
355     /* ExitProcess is used to set return code of _pclose */
356     printf("child output\n");
357     ExitProcess(0x37);
358 }
359 
360 static void test__popen(const char *name)
361 {
362     FILE *pipe;
363     char buf[1024];
364     int ret;
365 
366     sprintf(buf, "\"%s\" misc popen", name);
367     pipe = _popen(buf, "r");
368     ok(pipe != NULL, "_popen failed with error: %d\n", errno);
369 
370     fgets(buf, sizeof(buf), pipe);
371     ok(!strcmp(buf, "child output\n"), "buf = %s\n", buf);
372 
373     ret = _pclose(pipe);
374     ok(ret == 0x37, "_pclose returned %x, expected 0x37\n", ret);
375 
376     errno = 0xdeadbeef;
377     ret = _pclose((FILE*)0xdeadbeef);
378     ok(ret == -1, "_pclose returned %x, expected -1\n", ret);
379     if(p_set_errno)
380         ok(errno == EBADF, "errno = %d\n", errno);
381 }
382 
383 static void test__invalid_parameter(void)
384 {
385     if(!p__invalid_parameter) {
386         win_skip("_invalid_parameter not available\n");
387         return;
388     }
389 
390     p__invalid_parameter(NULL, NULL, NULL, 0, 0);
391 }
392 
393 struct qsort_test
394 {
395     int pos;
396     int *base;
397 
398     struct {
399         int l;
400         int r;
401     } cmp[64];
402 };
403 
404 static int __cdecl qsort_comp(void *ctx, const void *l, const void *r)
405 {
406     struct qsort_test *qt = ctx;
407 
408     if(qt) {
409         ok(qt->pos < 64, "qt->pos = %d\n", qt->pos);
410         ok(qt->cmp[qt->pos].l == (int*)l-qt->base,
411            "%d) l on %ld position\n", qt->pos, (long)((int*)l - qt->base));
412         ok(qt->cmp[qt->pos].r == (int*)r-qt->base,
413            "%d) r on %ld position\n", qt->pos, (long)((int*)r - qt->base));
414         qt->pos++;
415     }
416 
417     return *(int*)l%1000 - *(int*)r%1000;
418 }
419 
420 static void test_qsort_s(void)
421 {
422     static const int nonstable_test[] = {9000, 8001, 7002, 6003, 1003, 5004, 4005, 3006, 2007};
423     int tab[100], i;
424 
425     struct qsort_test small_sort = {
426         0, tab, {
427             {1, 0}, {2, 1}, {3, 2}, {4, 3}, {5, 4}, {6, 5}, {7, 6},
428             {1, 0}, {2, 1}, {3, 2}, {4, 3}, {5, 4}, {6, 5},
429             {1, 0}, {2, 1}, {3, 2}, {4, 3}, {5, 4},
430             {1, 0}, {2, 1}, {3, 2}, {4, 3},
431             {1, 0}, {2, 1}, {3, 2},
432             {1, 0}, {2, 1},
433             {1, 0}
434         }
435     }, small_sort2 = {
436         0, tab, {
437             {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
438             {1, 0}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1},
439             {1, 0}, {2, 1}, {3, 2}, {4, 2}, {5, 2},
440             {1, 0}, {2, 1}, {3, 2}, {4, 3},
441             {1, 0}, {2, 1}, {3, 2},
442             {1, 0}, {2, 1},
443             {1, 0}
444         }
445     }, quick_sort = {
446         0, tab, {
447             {0, 4}, {0, 8}, {4, 8},
448             {1, 4}, {2, 4}, {3, 4}, {5, 4}, {6, 4}, {7, 4}, {7, 4}, {6, 4},
449             {6, 4},
450             {8, 7},
451             {1, 0}, {2, 1}, {3, 2}, {4, 3}, {5, 4}, {6, 4},
452             {1, 0}, {2, 1}, {3, 2}, {4, 3}, {5, 3},
453             {1, 0}, {2, 1}, {3, 2}, {4, 2},
454             {1, 0}, {2, 1}, {3, 2},
455             {1, 0}, {2, 1},
456             {1, 0}
457         }
458     };
459 
460     if(!p_qsort_s) {
461         win_skip("qsort_s not available\n");
462         return;
463     }
464 
465     for(i=0; i<8; i++) tab[i] = i;
466     p_qsort_s(tab, 8, sizeof(int), qsort_comp, &small_sort);
467     ok(small_sort.pos == 28, "small_sort.pos = %d\n", small_sort.pos);
468     for(i=0; i<8; i++)
469         ok(tab[i] == i, "tab[%d] = %d\n", i, tab[i]);
470 
471     for(i=0; i<8; i++) tab[i] = 7-i;
472     p_qsort_s(tab, 8, sizeof(int), qsort_comp, &small_sort2);
473     ok(small_sort2.pos == 28, "small_sort2.pos = %d\n", small_sort2.pos);
474     for(i=0; i<8; i++)
475         ok(tab[i] == i, "tab[%d] = %d\n", i, tab[i]);
476 
477     for(i=0; i<9; i++) tab[i] = i;
478     tab[5] = 1;
479     tab[6] = 2;
480     p_qsort_s(tab, 9, sizeof(int), qsort_comp, &quick_sort);
481     ok(quick_sort.pos == 34, "quick_sort.pos = %d\n", quick_sort.pos);
482 
483     /* show that qsort is not stable */
484     for(i=0; i<9; i++) tab[i] = 8-i + 1000*(i+1);
485     tab[0] = 1003;
486     p_qsort_s(tab, 9, sizeof(int), qsort_comp, NULL);
487     for(i=0; i<9; i++)
488         ok(tab[i] == nonstable_test[i], "tab[%d] = %d, expected %d\n", i, tab[i], nonstable_test[i]);
489 
490     /* check if random data is sorted */
491     srand(0);
492     for(i=0; i<100; i++) tab[i] = rand()%1000;
493     p_qsort_s(tab, 100, sizeof(int), qsort_comp, NULL);
494     for(i=1; i<100; i++)
495         ok(tab[i-1] <= tab[i], "data sorted incorrectly on position %d: %d <= %d\n", i, tab[i-1], tab[i]);
496 
497     /* test if random permutation is sorted correctly */
498     for(i=0; i<100; i++) tab[i] = i;
499     for(i=0; i<100; i++) {
500         int b = rand()%100;
501         int e = rand()%100;
502 
503         if(b == e) continue;
504         tab[b] ^= tab[e];
505         tab[e] ^= tab[b];
506         tab[b] ^= tab[e];
507     }
508     p_qsort_s(tab, 100, sizeof(int), qsort_comp, NULL);
509     for(i=0; i<100; i++)
510         ok(tab[i] == i, "data sorted incorrectly on position %d: %d\n", i, tab[i]);
511 }
512 
513 static void test_math_functions(void)
514 {
515     double ret;
516 
517     errno = 0xdeadbeef;
518     p_atan(NAN);
519     ok(errno == EDOM, "errno = %d\n", errno);
520 
521     errno = 0xdeadbeef;
522     ret = p_atan(INFINITY);
523     ok(almost_equal(ret, 1.57079632679489661923), "ret = %lf\n", ret);
524     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
525 
526     errno = 0xdeadbeef;
527     ret = p_atan(-INFINITY);
528     ok(almost_equal(ret, -1.57079632679489661923), "ret = %lf\n", ret);
529     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
530 
531     errno = 0xdeadbeef;
532     p_tanh(NAN);
533     ok(errno == EDOM, "errno = %d\n", errno);
534 
535     errno = 0xdeadbeef;
536     ret = p_tanh(INFINITY);
537     ok(almost_equal(ret, 1.0), "ret = %lf\n", ret);
538     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
539 
540     errno = 0xdeadbeef;
541     p_exp(NAN);
542     ok(errno == EDOM, "errno = %d\n", errno);
543 
544     errno = 0xdeadbeef;
545     p_exp(INFINITY);
546     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
547 }
548 
549 static void __cdecl test_thread_func(void *end_thread_type)
550 {
551     if (end_thread_type == (void*)1)
552         _endthread();
553     else if (end_thread_type == (void*)2)
554         ExitThread(0);
555     else if (end_thread_type == (void*)3)
556         _endthreadex(0);
557 }
558 
559 static unsigned __stdcall test_thread_func_ex(void *arg)
560 {
561     _endthread();
562     return 0;
563 }
564 
565 static void test_thread_handle_close(void)
566 {
567     HANDLE hThread;
568     DWORD ret;
569 
570     /* _beginthread: handle is not closed on ExitThread and _endthreadex */
571     hThread = (HANDLE)_beginthread(test_thread_func, 0, NULL);
572     ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
573     WaitForSingleObject(hThread, INFINITE);
574     ret = CloseHandle(hThread);
575     ok(!ret, "ret = %d\n", ret);
576 
577     hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)1);
578     ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
579     WaitForSingleObject(hThread, INFINITE);
580     ret = CloseHandle(hThread);
581     ok(!ret, "ret = %d\n", ret);
582 
583     hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)2);
584     ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
585     Sleep(150);
586     ret = WaitForSingleObject(hThread, INFINITE);
587     ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
588     ret = CloseHandle(hThread);
589     ok(ret, "ret = %d\n", ret);
590 
591     hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)3);
592     ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
593     Sleep(150);
594     ret = WaitForSingleObject(hThread, INFINITE);
595     ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
596     ret = CloseHandle(hThread);
597     ok(ret, "ret = %d\n", ret);
598 
599     /* _beginthreadex: handle is not closed on _endthread */
600     hThread = (HANDLE)_beginthreadex(NULL,0, test_thread_func_ex, NULL, 0, NULL);
601     ok(hThread != NULL, "_beginthreadex failed (%d)\n", errno);
602     Sleep(150);
603     ret = WaitForSingleObject(hThread, INFINITE);
604     ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
605     ret = CloseHandle(hThread);
606     ok(ret, "ret = %d\n", ret);
607 }
608 
609 static int __cdecl _lfind_s_comp(void *ctx, const void *l, const void *r)
610 {
611     *(int *)ctx = 0xdeadc0de;
612     return *(int *)l - *(int *)r;
613 }
614 
615 static void test__lfind_s(void)
616 {
617     static const int tests[] = {9000, 8001, 7002, 6003, 1003, 5004, 4005, 3006, 2007};
618     unsigned int num;
619     void *found;
620     int ctx;
621     int key;
622 
623     if (!p_lfind_s)
624     {
625         win_skip("_lfind_s is not available\n");
626         return;
627     }
628 
629     key = 1234;
630     num = ARRAY_SIZE(tests);
631 
632     errno = 0xdeadbeef;
633     found = p_lfind_s(NULL, tests, &num, sizeof(int), _lfind_s_comp, NULL);
634     ok(errno == EINVAL, "errno = %d\n", errno);
635     ok(!found, "Expected NULL, got %p\n", found);
636 
637     errno = 0xdeadbeef;
638     found = p_lfind_s(&key, NULL, &num, sizeof(int), _lfind_s_comp, NULL);
639     ok(errno == EINVAL, "errno = %d\n", errno);
640     ok(!found, "Expected NULL, got %p\n", found);
641 
642     errno = 0xdeadbeef;
643     found = p_lfind_s(&key, tests, &num, 0, _lfind_s_comp, NULL);
644     ok(errno == EINVAL, "errno = %d\n", errno);
645     ok(!found, "Expected NULL, got %p\n", found);
646 
647     errno = 0xdeadbeef;
648     found = p_lfind_s(&key, tests, &num, sizeof(int), NULL, NULL);
649     ok(errno == EINVAL, "errno = %d\n", errno);
650     ok(!found, "Expected NULL, got %p\n", found);
651 
652     ctx = -1;
653     key = 9000;
654     errno = 0xdeadbeef;
655     found = p_lfind_s(&key, tests, &num, sizeof(int), _lfind_s_comp, &ctx);
656     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
657     ok(found == tests, "Expected %p, got %p\n", tests, found);
658     ok(ctx == 0xdeadc0de, "Expected 0xdeadc0de, got %x\n", ctx);
659 
660     ctx = -1;
661     key = 2007;
662     errno = 0xdeadbeef;
663     found = p_lfind_s(&key, tests, &num, sizeof(int), _lfind_s_comp, &ctx);
664     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
665     ok(found == tests+8, "Expected %p, got %p\n", tests+8, found);
666     ok(ctx == 0xdeadc0de, "Expected 0xdeadc0de, got %x\n", ctx);
667 
668     ctx = -1;
669     key = 1234;
670     errno = 0xdeadbeef;
671     found = p_lfind_s(&key, tests, &num, sizeof(int), _lfind_s_comp, &ctx);
672     ok(errno == 0xdeadbeef, "errno = %d\n", errno);
673     ok(!found, "Expected NULL, got %p\n", found);
674     ok(ctx == 0xdeadc0de, "Expected 0xdeadc0de, got %x\n", ctx);
675 }
676 
677 START_TEST(misc)
678 {
679     int arg_c;
680     char** arg_v;
681 
682     init();
683 
684     arg_c = winetest_get_mainargs(&arg_v);
685     if(arg_c >= 3) {
686         if(!strcmp(arg_v[2], "popen"))
687             test__popen_child();
688         else
689             ok(0, "invalid argument '%s'\n", arg_v[2]);
690 
691         return;
692     }
693 
694     test_rand_s();
695     test_I10_OUTPUT();
696     test_strerror_s();
697     test__get_doserrno();
698     test__get_errno();
699     test__set_doserrno();
700     test__set_errno();
701     test__popen(arg_v[0]);
702     test__invalid_parameter();
703     test_qsort_s();
704     test_math_functions();
705     test_thread_handle_close();
706     test__lfind_s();
707 }
708