msvcr90/tests: Added _getptd tests.
[wine] / dlls / msvcr90 / tests / msvcr90.c
1 /*
2  * Copyright 2010 Detlef Riekenberg
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <math.h>
23 #include <fcntl.h>
24 #include <share.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <locale.h>
28
29 #include <windef.h>
30 #include <winbase.h>
31 #include <errno.h>
32 #include "wine/test.h"
33
34 #define DEFINE_EXPECT(func) \
35     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
36
37 #define SET_EXPECT(func) \
38     expect_ ## func = TRUE
39
40 #define CHECK_EXPECT2(func) \
41     do { \
42         ok(expect_ ##func, "unexpected call " #func "\n"); \
43         called_ ## func = TRUE; \
44     }while(0)
45
46 #define CHECK_EXPECT(func) \
47     do { \
48         CHECK_EXPECT2(func); \
49         expect_ ## func = FALSE; \
50     }while(0)
51
52 #define CHECK_CALLED(func) \
53     do { \
54         ok(called_ ## func, "expected " #func "\n"); \
55         expect_ ## func = called_ ## func = FALSE; \
56     }while(0)
57
58 DEFINE_EXPECT(invalid_parameter_handler);
59
60 static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler);
61 typedef int (__cdecl *_INITTERM_E_FN)(void);
62 static int (__cdecl *p_initterm_e)(_INITTERM_E_FN *table, _INITTERM_E_FN *end);
63 static void* (__cdecl *p_encode_pointer)(void *);
64 static void* (__cdecl *p_decode_pointer)(void *);
65 static void* (__cdecl *p_encoded_null)(void);
66 static int *p_sys_nerr;
67 static int* (__cdecl *p__sys_nerr)(void);
68 static char **p_sys_errlist;
69 static char** (__cdecl *p__sys_errlist)(void);
70 static __int64 (__cdecl *p_strtoi64)(const char *, char **, int);
71 static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int);
72 static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int);
73 static int (__cdecl *p_wcsncat_s)(wchar_t *dst, size_t elem, const wchar_t *src, size_t count);
74 static void (__cdecl *p_qsort_s)(void *, size_t, size_t, int (__cdecl *)(void *, const void *, const void *), void *);
75 static int (__cdecl *p_controlfp_s)(unsigned int *, unsigned int, unsigned int);
76 static int (__cdecl *p_atoflt)(_CRT_FLOAT *, char *);
77 static unsigned int (__cdecl *p_set_abort_behavior)(unsigned int, unsigned int);
78 static int (__cdecl *p_sopen_s)(int*, const char*, int, int, int);
79 static int (__cdecl *p_wsopen_s)(int*, const wchar_t*, int, int, int);
80 static void* (__cdecl *p_realloc_crt)(void*, size_t);
81 static void* (__cdecl *p_malloc)(size_t);
82 static void (__cdecl *p_free)(void*);
83 static void* (__cdecl *p_getptd)(void);
84 static int* (__cdecl *p_errno)(void);
85 static __msvcrt_ulong* (__cdecl *p_doserrno)(void);
86 static void (__cdecl *p_srand)(unsigned int);
87 static char* (__cdecl *p_strtok)(char*, const char*);
88 static wchar_t* (__cdecl *p_wcstok)(wchar_t*, const wchar_t*);
89 static char* (__cdecl *p_strerror)(int);
90 static wchar_t* (__cdecl *p_wcserror)(int);
91 static char* (__cdecl *p_tmpnam)(char*);
92 static wchar_t* (__cdecl *p_wtmpnam)(wchar_t*);
93 static char* (__cdecl *p_asctime)(struct tm*);
94 static wchar_t* (__cdecl *p_wasctime)(struct tm*);
95 static struct tm* (__cdecl *p_localtime64)(__time64_t*);
96 static char* (__cdecl *p_ecvt)(double, int, int*, int*);
97 static int* (__cdecl *p_fpecode)(void);
98 static int (__cdecl *p_configthreadlocale)(int);
99 static void* (__cdecl *p_get_terminate)(void);
100 static void* (__cdecl *p_get_unexpected)(void);
101
102
103 /* type info */
104 typedef struct __type_info
105 {
106   void *vtable;
107   char *name;
108   char  mangled[16];
109 } type_info;
110
111
112 struct __type_info_node
113 {
114     void *memPtr;
115     struct __type_info_node* next;
116 };
117
118 static char* (WINAPI *p_type_info_name_internal_method)(type_info*, struct __type_info_node *);
119 static void  (WINAPI *ptype_info_dtor)(type_info*);
120
121 static void* (WINAPI *pEncodePointer)(void *);
122
123 static int cb_called[4];
124 static int g_qsort_s_context_counter;
125
126 static inline int almost_equal_f(float f1, float f2)
127 {
128     return f1-f2 > -1e-30 && f1-f2 < 1e-30;
129 }
130
131 /* ########## */
132
133 /* thiscall emulation */
134 /* Emulate a __thiscall */
135 #ifdef __i386__
136 #ifdef _MSC_VER
137 static inline void* do_call_func1(void *func, void *_this)
138 {
139   volatile void* retval = 0;
140   __asm
141   {
142     push ecx
143     mov ecx, _this
144     call func
145     mov retval, eax
146     pop ecx
147   }
148   return (void*)retval;
149 }
150
151 static inline void* do_call_func2(void *func, void *_this, const void* arg)
152 {
153   volatile void* retval = 0;
154   __asm
155   {
156     push ecx
157     push arg
158     mov ecx, _this
159     call func
160     mov retval, eax
161     pop ecx
162   }
163   return (void*)retval;
164 }
165 #else
166 static void* do_call_func1(void *func, void *_this)
167 {
168   void *ret, *dummy;
169   __asm__ __volatile__ ("call *%2"
170                         : "=a" (ret), "=c" (dummy)
171                         : "g" (func), "1" (_this)
172                         : "edx", "memory" );
173   return ret;
174 }
175
176 static void* do_call_func2(void *func, void *_this, const void* arg)
177 {
178   void *ret, *dummy;
179   __asm__ __volatile__ ("pushl %3\n\tcall *%2"
180                         : "=a" (ret), "=c" (dummy)
181                         : "r" (func), "r" (arg), "1" (_this)
182                         : "edx", "memory" );
183   return ret;
184 }
185 #endif
186
187 #define call_func1(func,_this)   do_call_func1(func,_this)
188 #define call_func2(func,_this,a) do_call_func2(func,_this,(const void*)a)
189
190 #else
191
192 #define call_func1(func,_this) func(_this)
193 #define call_func2(func,_this,a) func(_this,a)
194
195 #endif /* __i386__ */
196
197 static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
198         const wchar_t *function, const wchar_t *file,
199         unsigned line, uintptr_t arg)
200 {
201     CHECK_EXPECT(invalid_parameter_handler);
202     ok(expression == NULL, "expression is not NULL\n");
203     ok(function == NULL, "function is not NULL\n");
204     ok(file == NULL, "file is not NULL\n");
205     ok(line == 0, "line = %u\n", line);
206     ok(arg == 0, "arg = %lx\n", (UINT_PTR)arg);
207 }
208
209 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y)
210 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
211 static BOOL init(void)
212 {
213     HMODULE hcrt;
214     HMODULE hkernel32;
215
216     SetLastError(0xdeadbeef);
217     hcrt = LoadLibraryA("msvcr90.dll");
218     if (!hcrt) {
219         win_skip("msvcr90.dll not installed (got %d)\n", GetLastError());
220         return FALSE;
221     }
222
223     SET(p_set_invalid_parameter_handler, "_set_invalid_parameter_handler");
224     if(p_set_invalid_parameter_handler)
225         ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
226                 "Invalid parameter handler was already set\n");
227
228     SET(p_initterm_e, "_initterm_e");
229     SET(p_encode_pointer, "_encode_pointer");
230     SET(p_decode_pointer, "_decode_pointer");
231     SET(p_encoded_null, "_encoded_null");
232     SET(p_sys_nerr, "_sys_nerr");
233     SET(p__sys_nerr, "__sys_nerr");
234     SET(p_sys_errlist, "_sys_errlist");
235     SET(p__sys_errlist, "__sys_errlist");
236     SET(p_strtoi64, "_strtoi64");
237     SET(p_strtoui64, "_strtoui64");
238     SET(p_itoa_s, "_itoa_s");
239     SET(p_wcsncat_s,"wcsncat_s" );
240     SET(p_qsort_s, "qsort_s");
241     SET(p_controlfp_s, "_controlfp_s");
242     SET(p_atoflt, "_atoflt");
243     SET(p_set_abort_behavior, "_set_abort_behavior");
244     SET(p_sopen_s, "_sopen_s");
245     SET(p_wsopen_s, "_wsopen_s");
246     SET(p_realloc_crt, "_realloc_crt");
247     SET(p_malloc, "malloc");
248     SET(p_free, "free");
249     SET(p_getptd, "_getptd");
250     SET(p_errno, "_errno");
251     SET(p_doserrno, "__doserrno");
252     SET(p_srand, "srand");
253     SET(p_strtok, "strtok");
254     SET(p_wcstok, "wcstok");
255     SET(p_strerror, "strerror");
256     SET(p_wcserror, "_wcserror");
257     SET(p_tmpnam, "tmpnam");
258     SET(p_wtmpnam, "_wtmpnam");
259     SET(p_asctime, "asctime");
260     SET(p_wasctime, "_wasctime");
261     SET(p_localtime64, "_localtime64");
262     SET(p_ecvt, "_ecvt");
263     SET(p_fpecode, "__fpecode");
264     SET(p_configthreadlocale, "_configthreadlocale");
265     SET(p_get_terminate, "_get_terminate");
266     SET(p_get_unexpected, "_get_unexpected");
267     if (sizeof(void *) == 8)
268     {
269         SET(p_type_info_name_internal_method, "?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z");
270         SET(ptype_info_dtor, "??1type_info@@UEAA@XZ");
271     }
272     else
273     {
274         SET(p_type_info_name_internal_method, "?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z");
275         SET(ptype_info_dtor, "??1type_info@@UAE@XZ");
276     }
277
278     hkernel32 = GetModuleHandleA("kernel32.dll");
279     pEncodePointer = (void *) GetProcAddress(hkernel32, "EncodePointer");
280     return TRUE;
281 }
282
283 static int __cdecl initterm_cb0(void)
284 {
285     cb_called[0]++;
286     return 0;
287 }
288
289 static int __cdecl initterm_cb1(void)
290 {
291     cb_called[1]++;
292     return 1;
293 }
294
295 static int __cdecl initterm_cb2(void)
296 {
297     cb_called[2]++;
298     return 2;
299 }
300
301
302 static void test__initterm_e(void)
303 {
304     _INITTERM_E_FN table[4];
305     int res;
306
307     memset(table, 0, sizeof(table));
308
309     memset(cb_called, 0, sizeof(cb_called));
310     errno = 0xdeadbeef;
311     res = p_initterm_e(table, table);
312     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
313         "got %d with 0x%x {%d, %d, %d}\n",
314         res, errno, cb_called[0], cb_called[1], cb_called[2]);
315
316     memset(cb_called, 0, sizeof(cb_called));
317     errno = 0xdeadbeef;
318     res = p_initterm_e(table, NULL);
319     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
320         "got %d with 0x%x {%d, %d, %d}\n",
321         res, errno, cb_called[0], cb_called[1], cb_called[2]);
322
323     if (0) {
324         /* this crash on Windows */
325         errno = 0xdeadbeef;
326         res = p_initterm_e(NULL, table);
327         trace("got %d with 0x%x\n", res, errno);
328     }
329
330     table[0] = initterm_cb0;
331     memset(cb_called, 0, sizeof(cb_called));
332     errno = 0xdeadbeef;
333     res = p_initterm_e(table, &table[1]);
334     ok( !res && (cb_called[0] == 1) && !cb_called[1] && !cb_called[2],
335         "got %d with 0x%x {%d, %d, %d}\n",
336         res, errno, cb_called[0], cb_called[1], cb_called[2]);
337
338
339     /* init-function returning failure */
340     table[1] = initterm_cb1;
341     memset(cb_called, 0, sizeof(cb_called));
342     errno = 0xdeadbeef;
343     res = p_initterm_e(table, &table[3]);
344     ok( (res == 1) && (cb_called[0] == 1) && (cb_called[1] == 1) && !cb_called[2],
345         "got %d with 0x%x {%d, %d, %d}\n",
346         res, errno, cb_called[0], cb_called[1], cb_called[2]);
347
348     /* init-function not called, when end < start */
349     memset(cb_called, 0, sizeof(cb_called));
350     errno = 0xdeadbeef;
351     res = p_initterm_e(&table[3], table);
352     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
353         "got %d with 0x%x {%d, %d, %d}\n",
354         res, errno, cb_called[0], cb_called[1], cb_called[2]);
355
356     /* initialization stop after first non-zero result */
357     table[2] = initterm_cb0;
358     memset(cb_called, 0, sizeof(cb_called));
359     errno = 0xdeadbeef;
360     res = p_initterm_e(table, &table[3]);
361     ok( (res == 1) && (cb_called[0] == 1) && (cb_called[1] == 1) && !cb_called[2],
362         "got %d with 0x%x {%d, %d, %d}\n",
363         res, errno, cb_called[0], cb_called[1], cb_called[2]);
364
365     /* NULL pointer in the array are skipped */
366     table[1] = NULL;
367     table[2] = initterm_cb2;
368     memset(cb_called, 0, sizeof(cb_called));
369     errno = 0xdeadbeef;
370     res = p_initterm_e(table, &table[3]);
371     ok( (res == 2) && (cb_called[0] == 1) && !cb_called[1] && (cb_called[2] == 1),
372         "got %d with 0x%x {%d, %d, %d}\n",
373         res, errno, cb_called[0], cb_called[1], cb_called[2]);
374
375 }
376
377 /* Beware that _encode_pointer is a NOP before XP
378    (the parameter is returned unchanged) */
379 static void test__encode_pointer(void)
380 {
381     void *ptr, *res;
382
383     ptr = (void*)0xdeadbeef;
384     res = p_encode_pointer(ptr);
385     res = p_decode_pointer(res);
386     ok(res == ptr, "Pointers are different after encoding and decoding\n");
387
388     ok(p_encoded_null() == p_encode_pointer(NULL), "Error encoding null\n");
389
390     ptr = p_encode_pointer(p_encode_pointer);
391     ok(p_decode_pointer(ptr) == p_encode_pointer, "Error decoding pointer\n");
392
393     /* Not present before XP */
394     if (!pEncodePointer) {
395         win_skip("EncodePointer not found\n");
396         return;
397     }
398
399     res = pEncodePointer(p_encode_pointer);
400     ok(ptr == res, "_encode_pointer produced different result than EncodePointer\n");
401
402 }
403
404 static void test_error_messages(void)
405 {
406     int *size, size_copy;
407
408     size = p__sys_nerr();
409     size_copy = *size;
410     ok(*p_sys_nerr == *size, "_sys_nerr = %u, size = %u\n", *p_sys_nerr, *size);
411
412     *size = 20;
413     ok(*p_sys_nerr == *size, "_sys_nerr = %u, size = %u\n", *p_sys_nerr, *size);
414
415     *size = size_copy;
416
417     ok(*p_sys_errlist == *(p__sys_errlist()), "p_sys_errlist != p__sys_errlist()\n");
418 }
419
420 static void test__strtoi64(void)
421 {
422     __int64 res;
423     unsigned __int64 ures;
424
425     errno = 0xdeadbeef;
426     SET_EXPECT(invalid_parameter_handler);
427     res = p_strtoi64(NULL, NULL, 10);
428     ok(res == 0, "res != 0\n");
429     CHECK_CALLED(invalid_parameter_handler);
430
431     SET_EXPECT(invalid_parameter_handler);
432     res = p_strtoi64("123", NULL, 1);
433     ok(res == 0, "res != 0\n");
434     CHECK_CALLED(invalid_parameter_handler);
435
436     SET_EXPECT(invalid_parameter_handler);
437     res = p_strtoi64("123", NULL, 37);
438     ok(res == 0, "res != 0\n");
439     CHECK_CALLED(invalid_parameter_handler);
440
441     SET_EXPECT(invalid_parameter_handler);
442     ures = p_strtoui64(NULL, NULL, 10);
443     ok(ures == 0, "res = %d\n", (int)ures);
444     CHECK_CALLED(invalid_parameter_handler);
445
446     SET_EXPECT(invalid_parameter_handler);
447     ures = p_strtoui64("123", NULL, 1);
448     ok(ures == 0, "res = %d\n", (int)ures);
449     CHECK_CALLED(invalid_parameter_handler);
450
451     SET_EXPECT(invalid_parameter_handler);
452     ures = p_strtoui64("123", NULL, 37);
453     ok(ures == 0, "res = %d\n", (int)ures);
454     CHECK_CALLED(invalid_parameter_handler);
455     ok(errno == 0xdeadbeef, "errno = %x\n", errno);
456 }
457
458 static void test__itoa_s(void)
459 {
460     errno_t ret;
461     char buffer[33];
462
463     /* _itoa_s (on msvcr90) doesn't set errno (in case of errors) while msvcrt does
464      * as we always set errno in our msvcrt implementation, don't test here that errno
465      * isn't changed
466      */
467     SET_EXPECT(invalid_parameter_handler);
468     ret = p_itoa_s(0, NULL, 0, 0);
469     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
470     CHECK_CALLED(invalid_parameter_handler);
471
472     memset(buffer, 'X', sizeof(buffer));
473     SET_EXPECT(invalid_parameter_handler);
474     ret = p_itoa_s(0, buffer, 0, 0);
475     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
476     ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n");
477     CHECK_CALLED(invalid_parameter_handler);
478
479     memset(buffer, 'X', sizeof(buffer));
480     SET_EXPECT(invalid_parameter_handler);
481     ret = p_itoa_s(0, buffer, sizeof(buffer), 0);
482     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
483     ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
484     CHECK_CALLED(invalid_parameter_handler);
485
486     memset(buffer, 'X', sizeof(buffer));
487     SET_EXPECT(invalid_parameter_handler);
488     ret = p_itoa_s(0, buffer, sizeof(buffer), 64);
489     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
490     ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
491     CHECK_CALLED(invalid_parameter_handler);
492
493     memset(buffer, 'X', sizeof(buffer));
494     SET_EXPECT(invalid_parameter_handler);
495     ret = p_itoa_s(12345678, buffer, 4, 10);
496     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
497     ok(!memcmp(buffer, "\000765", 4),
498        "Expected the output buffer to be null terminated with truncated output\n");
499     CHECK_CALLED(invalid_parameter_handler);
500
501     memset(buffer, 'X', sizeof(buffer));
502     SET_EXPECT(invalid_parameter_handler);
503     ret = p_itoa_s(12345678, buffer, 8, 10);
504     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
505     ok(!memcmp(buffer, "\0007654321", 8),
506        "Expected the output buffer to be null terminated with truncated output\n");
507     CHECK_CALLED(invalid_parameter_handler);
508
509     memset(buffer, 'X', sizeof(buffer));
510     SET_EXPECT(invalid_parameter_handler);
511     ret = p_itoa_s(-12345678, buffer, 9, 10);
512     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
513     ok(!memcmp(buffer, "\00087654321", 9),
514        "Expected the output buffer to be null terminated with truncated output\n");
515     CHECK_CALLED(invalid_parameter_handler);
516
517     ret = p_itoa_s(12345678, buffer, 9, 10);
518     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
519     ok(!strcmp(buffer, "12345678"),
520        "Expected output buffer string to be \"12345678\", got \"%s\"\n",
521        buffer);
522
523     ret = p_itoa_s(43690, buffer, sizeof(buffer), 2);
524     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
525     ok(!strcmp(buffer, "1010101010101010"),
526        "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n",
527        buffer);
528
529     ret = p_itoa_s(1092009, buffer, sizeof(buffer), 36);
530     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
531     ok(!strcmp(buffer, "nell"),
532        "Expected output buffer string to be \"nell\", got \"%s\"\n",
533        buffer);
534
535     ret = p_itoa_s(5704, buffer, sizeof(buffer), 18);
536     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
537     ok(!strcmp(buffer, "hag"),
538        "Expected output buffer string to be \"hag\", got \"%s\"\n",
539        buffer);
540
541     ret = p_itoa_s(-12345678, buffer, sizeof(buffer), 10);
542     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
543     ok(!strcmp(buffer, "-12345678"),
544        "Expected output buffer string to be \"-12345678\", got \"%s\"\n",
545        buffer);
546 }
547
548 static void test_wcsncat_s(void)
549 {
550     static wchar_t abcW[] = {'a','b','c',0};
551     int ret;
552     wchar_t dst[4];
553     wchar_t src[4];
554
555     memcpy(src, abcW, sizeof(abcW));
556     dst[0] = 0;
557     SET_EXPECT(invalid_parameter_handler);
558     ret = p_wcsncat_s(NULL, 4, src, 4);
559     ok(ret == EINVAL, "err = %d\n", ret);
560     CHECK_CALLED(invalid_parameter_handler);
561
562     SET_EXPECT(invalid_parameter_handler);
563     ret = p_wcsncat_s(dst, 0, src, 4);
564     ok(ret == EINVAL, "err = %d\n", ret);
565     CHECK_CALLED(invalid_parameter_handler);
566
567     SET_EXPECT(invalid_parameter_handler);
568     ret = p_wcsncat_s(dst, 0, src, _TRUNCATE);
569     ok(ret == EINVAL, "err = %d\n", ret);
570     CHECK_CALLED(invalid_parameter_handler);
571
572     ret = p_wcsncat_s(dst, 4, NULL, 0);
573     ok(ret == 0, "err = %d\n", ret);
574
575     dst[0] = 0;
576     SET_EXPECT(invalid_parameter_handler);
577     ret = p_wcsncat_s(dst, 2, src, 4);
578     ok(ret == ERANGE, "err = %d\n", ret);
579     CHECK_CALLED(invalid_parameter_handler);
580
581     dst[0] = 0;
582     ret = p_wcsncat_s(dst, 2, src, _TRUNCATE);
583     ok(ret == STRUNCATE, "err = %d\n", ret);
584     ok(dst[0] == 'a' && dst[1] == 0, "dst is %s\n", wine_dbgstr_w(dst));
585
586     memcpy(dst, abcW, sizeof(abcW));
587     dst[3] = 'd';
588     SET_EXPECT(invalid_parameter_handler);
589     ret = p_wcsncat_s(dst, 4, src, 4);
590     ok(ret == EINVAL, "err = %d\n", ret);
591     CHECK_CALLED(invalid_parameter_handler);
592 }
593
594 /* Based on dlls/ntdll/tests/string.c */
595 static __cdecl int intcomparefunc(void *context, const void *a, const void *b)
596 {
597     const int *p = a, *q = b;
598
599     ok (a != b, "must never get the same pointer\n");
600     ++*(int *) context;
601
602     return *p - *q;
603 }
604
605 static __cdecl int charcomparefunc(void *context, const void *a, const void *b)
606 {
607     const char *p = a, *q = b;
608
609     ok (a != b, "must never get the same pointer\n");
610     ++*(int *) context;
611
612     return *p - *q;
613 }
614
615 static __cdecl int strcomparefunc(void *context, const void *a, const void *b)
616 {
617     const char * const *p = a;
618     const char * const *q = b;
619
620     ok (a != b, "must never get the same pointer\n");
621     ++*(int *) context;
622
623     return lstrcmpA(*p, *q);
624 }
625
626 static void test_qsort_s(void)
627 {
628     int arr[5] = { 23, 42, 8, 4, 16 };
629     int arr2[5] = { 23, 42, 8, 4, 16 };
630     char carr[5] = { 42, 23, 4, 8, 16 };
631     const char *strarr[7] = {
632     "Hello",
633     "Wine",
634     "World",
635     "!",
636     "Hopefully",
637     "Sorted",
638     "."
639     };
640
641     SET_EXPECT(invalid_parameter_handler);
642     p_qsort_s(NULL, 0, 0, NULL, NULL);
643     CHECK_CALLED(invalid_parameter_handler);
644
645     SET_EXPECT(invalid_parameter_handler);
646     p_qsort_s(NULL, 0, 0, intcomparefunc, NULL);
647     CHECK_CALLED(invalid_parameter_handler);
648
649     SET_EXPECT(invalid_parameter_handler);
650     p_qsort_s(NULL, 0, sizeof(int), NULL, NULL);
651     CHECK_CALLED(invalid_parameter_handler);
652
653     SET_EXPECT(invalid_parameter_handler);
654     p_qsort_s(NULL, 1, sizeof(int), intcomparefunc, NULL);
655     CHECK_CALLED(invalid_parameter_handler);
656
657     g_qsort_s_context_counter = 0;
658     p_qsort_s(NULL, 0, sizeof(int), intcomparefunc, NULL);
659     ok(g_qsort_s_context_counter == 0, "callback shouldn't have been called\n");
660
661     /* overflow without side effects, other overflow values crash */
662     g_qsort_s_context_counter = 0;
663     p_qsort_s((void*)arr2, (((size_t)1) << (8*sizeof(size_t) - 1)) + 1, sizeof(int), intcomparefunc, &g_qsort_s_context_counter);
664     ok(g_qsort_s_context_counter == 0, "callback shouldn't have been called\n");
665     ok(arr2[0] == 23, "should remain unsorted, arr2[0] is %d\n", arr2[0]);
666     ok(arr2[1] == 42, "should remain unsorted, arr2[1] is %d\n", arr2[1]);
667     ok(arr2[2] == 8,  "should remain unsorted, arr2[2] is %d\n", arr2[2]);
668     ok(arr2[3] == 4,  "should remain unsorted, arr2[3] is %d\n", arr2[3]);
669
670     g_qsort_s_context_counter = 0;
671     p_qsort_s((void*)arr, 0, sizeof(int), intcomparefunc, &g_qsort_s_context_counter);
672     ok(g_qsort_s_context_counter == 0, "callback shouldn't have been called\n");
673     ok(arr[0] == 23, "badly sorted, nmemb=0, arr[0] is %d\n", arr[0]);
674     ok(arr[1] == 42, "badly sorted, nmemb=0, arr[1] is %d\n", arr[1]);
675     ok(arr[2] == 8,  "badly sorted, nmemb=0, arr[2] is %d\n", arr[2]);
676     ok(arr[3] == 4,  "badly sorted, nmemb=0, arr[3] is %d\n", arr[3]);
677     ok(arr[4] == 16, "badly sorted, nmemb=0, arr[4] is %d\n", arr[4]);
678
679     g_qsort_s_context_counter = 0;
680     p_qsort_s((void*)arr, 1, sizeof(int), intcomparefunc, &g_qsort_s_context_counter);
681     ok(g_qsort_s_context_counter == 0, "callback shouldn't have been called\n");
682     ok(arr[0] == 23, "badly sorted, nmemb=1, arr[0] is %d\n", arr[0]);
683     ok(arr[1] == 42, "badly sorted, nmemb=1, arr[1] is %d\n", arr[1]);
684     ok(arr[2] == 8,  "badly sorted, nmemb=1, arr[2] is %d\n", arr[2]);
685     ok(arr[3] == 4,  "badly sorted, nmemb=1, arr[3] is %d\n", arr[3]);
686     ok(arr[4] == 16, "badly sorted, nmemb=1, arr[4] is %d\n", arr[4]);
687
688     SET_EXPECT(invalid_parameter_handler);
689     g_qsort_s_context_counter = 0;
690     p_qsort_s((void*)arr, 5, 0, intcomparefunc, &g_qsort_s_context_counter);
691     ok(g_qsort_s_context_counter == 0, "callback shouldn't have been called\n");
692     ok(arr[0] == 23, "badly sorted, size=0, arr[0] is %d\n", arr[0]);
693     ok(arr[1] == 42, "badly sorted, size=0, arr[1] is %d\n", arr[1]);
694     ok(arr[2] == 8,  "badly sorted, size=0, arr[2] is %d\n", arr[2]);
695     ok(arr[3] == 4,  "badly sorted, size=0, arr[3] is %d\n", arr[3]);
696     ok(arr[4] == 16, "badly sorted, size=0, arr[4] is %d\n", arr[4]);
697     CHECK_CALLED(invalid_parameter_handler);
698
699     g_qsort_s_context_counter = 0;
700     p_qsort_s((void*)arr, 5, sizeof(int), intcomparefunc, &g_qsort_s_context_counter);
701     ok(g_qsort_s_context_counter > 0, "callback wasn't called\n");
702     ok(arr[0] == 4,  "badly sorted, arr[0] is %d\n", arr[0]);
703     ok(arr[1] == 8,  "badly sorted, arr[1] is %d\n", arr[1]);
704     ok(arr[2] == 16, "badly sorted, arr[2] is %d\n", arr[2]);
705     ok(arr[3] == 23, "badly sorted, arr[3] is %d\n", arr[3]);
706     ok(arr[4] == 42, "badly sorted, arr[4] is %d\n", arr[4]);
707
708     g_qsort_s_context_counter = 0;
709     p_qsort_s((void*)carr, 5, sizeof(char), charcomparefunc, &g_qsort_s_context_counter);
710     ok(g_qsort_s_context_counter > 0, "callback wasn't called\n");
711     ok(carr[0] == 4,  "badly sorted, carr[0] is %d\n", carr[0]);
712     ok(carr[1] == 8,  "badly sorted, carr[1] is %d\n", carr[1]);
713     ok(carr[2] == 16, "badly sorted, carr[2] is %d\n", carr[2]);
714     ok(carr[3] == 23, "badly sorted, carr[3] is %d\n", carr[3]);
715     ok(carr[4] == 42, "badly sorted, carr[4] is %d\n", carr[4]);
716
717     g_qsort_s_context_counter = 0;
718     p_qsort_s((void*)strarr, 7, sizeof(char*), strcomparefunc, &g_qsort_s_context_counter);
719     ok(g_qsort_s_context_counter > 0, "callback wasn't called\n");
720     ok(!strcmp(strarr[0],"!"),  "badly sorted, strarr[0] is %s\n", strarr[0]);
721     ok(!strcmp(strarr[1],"."),  "badly sorted, strarr[1] is %s\n", strarr[1]);
722     ok(!strcmp(strarr[2],"Hello"),  "badly sorted, strarr[2] is %s\n", strarr[2]);
723     ok(!strcmp(strarr[3],"Hopefully"),  "badly sorted, strarr[3] is %s\n", strarr[3]);
724     ok(!strcmp(strarr[4],"Sorted"),  "badly sorted, strarr[4] is %s\n", strarr[4]);
725     ok(!strcmp(strarr[5],"Wine"),  "badly sorted, strarr[5] is %s\n", strarr[5]);
726     ok(!strcmp(strarr[6],"World"),  "badly sorted, strarr[6] is %s\n", strarr[6]);
727 }
728
729 static void test_controlfp_s(void)
730 {
731     unsigned int cur;
732     int ret;
733
734     SET_EXPECT(invalid_parameter_handler);
735     ret = p_controlfp_s( NULL, ~0, ~0 );
736     ok( ret == EINVAL, "wrong result %d\n", ret );
737     CHECK_CALLED(invalid_parameter_handler);
738
739     cur = 0xdeadbeef;
740     SET_EXPECT(invalid_parameter_handler);
741     ret = p_controlfp_s( &cur, ~0, ~0 );
742     ok( ret == EINVAL, "wrong result %d\n", ret );
743     ok( cur != 0xdeadbeef, "value not set\n" );
744     CHECK_CALLED(invalid_parameter_handler);
745
746     cur = 0xdeadbeef;
747     ret = p_controlfp_s( &cur, 0, 0 );
748     ok( !ret, "wrong result %d\n", ret );
749     ok( cur != 0xdeadbeef, "value not set\n" );
750
751     SET_EXPECT(invalid_parameter_handler);
752     cur = 0xdeadbeef;
753     ret = p_controlfp_s( &cur, 0x80000000, 0x80000000 );
754     ok( ret == EINVAL, "wrong result %d\n", ret );
755     ok( cur != 0xdeadbeef, "value not set\n" );
756     CHECK_CALLED(invalid_parameter_handler);
757
758     cur = 0xdeadbeef;
759     /* mask is only checked when setting invalid bits */
760     ret = p_controlfp_s( &cur, 0, 0x80000000 );
761     ok( !ret, "wrong result %d\n", ret );
762     ok( cur != 0xdeadbeef, "value not set\n" );
763 }
764
765 typedef struct
766 {
767     const char *str;
768     float flt;
769     int ret;
770 } _atoflt_test;
771
772 static const _atoflt_test _atoflt_testdata[] = {
773     { "12.1", 12.1, 0 },
774     { "-13.721", -13.721, 0 },
775     { "INF", 0.0, 0 },
776     { ".21e12", 0.21e12, 0 },
777     { "214353e-3", 214.353, 0 },
778     { "1d9999999999999999999", 0.0, _OVERFLOW },
779     { "  d10", 0.0, 0 },
780     /* more significant digits */
781     { "1.23456789", 1.23456789, 0 },
782     { "1.23456789e1", 12.3456789, 0 },
783     { "1e39", 0.0, _OVERFLOW },
784     { "1e-39", 0.0, _UNDERFLOW },
785     { NULL }
786 };
787
788 static void test__atoflt(void)
789 {
790     _CRT_FLOAT flt;
791     int ret, i = 0;
792
793 if (0)
794 {
795     /* crashes on native */
796     p_atoflt(NULL, NULL);
797     p_atoflt(NULL, (char*)_atoflt_testdata[0].str);
798     p_atoflt(&flt, NULL);
799 }
800
801     while (_atoflt_testdata[i].str)
802     {
803         ret = p_atoflt(&flt, (char*)_atoflt_testdata[i].str);
804         ok(ret == _atoflt_testdata[i].ret, "got ret %d, expected ret %d, for %s\n", ret,
805             _atoflt_testdata[i].ret, _atoflt_testdata[i].str);
806
807         if (ret == 0)
808           ok(almost_equal_f(flt.f, _atoflt_testdata[i].flt), "got %f, expected %f, for %s\n", flt.f,
809               _atoflt_testdata[i].flt, _atoflt_testdata[i].str);
810
811         i++;
812     }
813 }
814
815 static void test__set_abort_behavior(void)
816 {
817     unsigned int res;
818
819     /* default is _WRITE_ABORT_MSG | _CALL_REPORTFAULT */
820     res = p_set_abort_behavior(0, 0);
821     ok (res == (_WRITE_ABORT_MSG | _CALL_REPORTFAULT),
822         "got 0x%x (expected 0x%x)\n", res, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
823
824     /* no internal mask */
825     p_set_abort_behavior(0xffffffff, 0xffffffff);
826     res = p_set_abort_behavior(0, 0);
827     ok (res == 0xffffffff, "got 0x%x (expected 0x%x)\n", res, 0xffffffff);
828
829     /* set to default value */
830     p_set_abort_behavior(_WRITE_ABORT_MSG | _CALL_REPORTFAULT, 0xffffffff);
831 }
832
833 static void test__sopen_s(void)
834 {
835     int ret, fd;
836
837     SET_EXPECT(invalid_parameter_handler);
838     ret = p_sopen_s(NULL, "test", _O_RDONLY, _SH_DENYNO, _S_IREAD);
839     ok(ret == EINVAL, "got %d, expected EINVAL\n", ret);
840     CHECK_CALLED(invalid_parameter_handler);
841
842     fd = 0xdead;
843     ret = p_sopen_s(&fd, "test", _O_RDONLY, _SH_DENYNO, _S_IREAD);
844     ok(ret == ENOENT, "got %d, expected ENOENT\n", ret);
845     ok(fd == -1, "got %d\n", fd);
846 }
847
848 static void test__wsopen_s(void)
849 {
850     wchar_t testW[] = {'t','e','s','t',0};
851     int ret, fd;
852
853     SET_EXPECT(invalid_parameter_handler);
854     ret = p_wsopen_s(NULL, testW, _O_RDONLY, _SH_DENYNO, _S_IREAD);
855     ok(ret == EINVAL, "got %d, expected EINVAL\n", ret);
856     CHECK_CALLED(invalid_parameter_handler);
857
858     fd = 0xdead;
859     ret = p_wsopen_s(&fd, testW, _O_RDONLY, _SH_DENYNO, _S_IREAD);
860     ok(ret == ENOENT, "got %d, expected ENOENT\n", ret);
861     ok(fd == -1, "got %d\n", fd);
862 }
863
864 static void test__realloc_crt(void)
865 {
866     void *mem;
867
868 if (0)
869 {
870     /* crashes on some systems starting Vista */
871     p_realloc_crt(NULL, 10);
872 }
873
874     mem = p_malloc(10);
875     ok(mem != NULL, "memory not allocated\n");
876
877     mem = p_realloc_crt(mem, 20);
878     ok(mem != NULL, "memory not reallocated\n");
879
880     mem = p_realloc_crt(mem, 0);
881     ok(mem == NULL, "memory not freed\n");
882
883     mem = p_realloc_crt(NULL, 0);
884     ok(mem != NULL, "memory not (re)allocated for size 0\n");
885     p_free(mem);
886 }
887
888 static void test_typeinfo(void)
889 {
890     static type_info t1 = { NULL, NULL,{'.','?','A','V','t','e','s','t','1','@','@',0,0,0,0,0 } };
891     struct __type_info_node node;
892     char *name;
893
894     /* name */
895     t1.name = NULL;
896     node.memPtr = NULL;
897     node.next = NULL;
898     name = call_func2(p_type_info_name_internal_method, &t1, &node);
899     ok(name != NULL, "got %p\n", name);
900     ok(name && t1.name && !strcmp(name, t1.name), "bad name '%s' for t1\n", name);
901
902     ok(t1.name && !strcmp(t1.name, "class test1"), "demangled to '%s' for t1\n", t1.name);
903     call_func1(ptype_info_dtor, &t1);
904 }
905
906 /* Keep in sync with msvcrt/msvcrt.h */
907 struct __thread_data {
908     DWORD                           tid;
909     HANDLE                          handle;
910     int                             thread_errno;
911     __msvcrt_ulong                  thread_doserrno;
912     int                             unk1;
913     unsigned int                    random_seed;
914     char                            *strtok_next;
915     wchar_t                         *wcstok_next;
916     unsigned char                   *mbstok_next;
917     char                            *strerror_buffer;
918     wchar_t                         *wcserror_buffer;
919     char                            *tmpnam_buffer;
920     wchar_t                         *wtmpnam_buffer;
921     void                            *unk2[2];
922     char                            *asctime_buffer;
923     wchar_t                         *wasctime_buffer;
924     struct tm                       *time_buffer;
925     char                            *efcvt_buffer;
926     int                             unk3[2];
927     void                            *unk4[4];
928     int                             fpecode;
929     pthreadmbcinfo                  mbcinfo;
930     pthreadlocinfo                  locinfo;
931     BOOL                            have_locale;
932     int                             unk5[1];
933     void*                           terminate_handler;
934     void*                           unexpected_handler;
935     void*                           se_translator;
936     void                            *unk6[3];
937     int                             unk7;
938     EXCEPTION_RECORD                *exc_record;
939 };
940
941 static void test_getptd(void)
942 {
943     struct __thread_data *ptd = p_getptd();
944     DWORD tid = GetCurrentThreadId();
945     wchar_t testW[] = {'t','e','s','t',0}, tW[] = {'t',0}, *wp;
946     char test[] = "test", *p;
947     struct tm time;
948     __time64_t secs = 0;
949     int dec, sign;
950     void *mbcinfo, *locinfo;
951
952     ok(ptd->tid == tid, "ptd->tid = %x, expected %x\n", ptd->tid, tid);
953     ok(ptd->handle == INVALID_HANDLE_VALUE, "ptd->handle = %p\n", ptd->handle);
954     ok(p_errno() == &ptd->thread_errno, "ptd->thread_errno is different then _errno()\n");
955     ok(p_doserrno() == &ptd->thread_doserrno, "ptd->thread_doserrno is different then __doserrno()\n");
956     p_srand(1234);
957     ok(ptd->random_seed == 1234, "ptd->random_seed = %d\n", ptd->random_seed);
958     p = p_strtok(test, "t");
959     ok(ptd->strtok_next == p+3, "ptd->strtok_next is incorrect\n");
960     wp = p_wcstok(testW, tW);
961     ok(ptd->wcstok_next == wp+3, "ptd->wcstok_next is incorrect\n");
962     ok(p_strerror(0) == ptd->strerror_buffer, "ptd->strerror_buffer is incorrect\n");
963     ok(p_wcserror(0) == ptd->wcserror_buffer, "ptd->wcserror_buffer is incorrect\n");
964     ok(p_tmpnam(NULL) == ptd->tmpnam_buffer, "ptd->tmpnam_buffer is incorrect\n");
965     ok(p_wtmpnam(NULL) == ptd->wtmpnam_buffer, "ptd->wtmpnam_buffer is incorrect\n");
966     memset(&time, 0, sizeof(time));
967     time.tm_mday = 1;
968     ok(p_asctime(&time) == ptd->asctime_buffer, "ptd->asctime_buffer is incorrect\n");
969     ok(p_wasctime(&time) == ptd->wasctime_buffer, "ptd->wasctime_buffer is incorrect\n");
970     ok(p_localtime64(&secs) == ptd->time_buffer, "ptd->time_buffer is incorrect\n");
971     ok(p_ecvt(3.12, 1, &dec, &sign) == ptd->efcvt_buffer, "ptd->efcvt_buffer is incorrect\n");
972     ok(p_fpecode() == &ptd->fpecode, "ptd->fpecode is incorrect\n");
973     mbcinfo = ptd->mbcinfo;
974     locinfo = ptd->locinfo;
975     todo_wine ok(ptd->have_locale == 1, "ptd->have_locale = %x\n", ptd->have_locale);
976     p_configthreadlocale(1);
977     todo_wine ok(mbcinfo == ptd->mbcinfo, "ptd->mbcinfo != mbcinfo\n");
978     todo_wine ok(locinfo == ptd->locinfo, "ptd->locinfo != locinfo\n");
979     todo_wine ok(ptd->have_locale == 3, "ptd->have_locale = %x\n", ptd->have_locale);
980     ok(p_get_terminate() == ptd->terminate_handler, "ptd->terminate_handler != _get_terminate()\n");
981     ok(p_get_unexpected() == ptd->unexpected_handler, "ptd->unexpected_handler != _get_unexpected()\n");
982 }
983
984 START_TEST(msvcr90)
985 {
986     if(!init())
987         return;
988
989     test__initterm_e();
990     test__encode_pointer();
991     test_error_messages();
992     test__strtoi64();
993     test__itoa_s();
994     test_wcsncat_s();
995     test_qsort_s();
996     test_controlfp_s();
997     test__atoflt();
998     test__set_abort_behavior();
999     test__sopen_s();
1000     test__wsopen_s();
1001     test__realloc_crt();
1002     test_typeinfo();
1003     test_getptd();
1004 }