crt: tests: add new test t_wassert This test is similar to t_assert, except it tests CRT function `_wassert`. Unlike `_assert`, CRT function `_wassert` properly behaves in case when `stderr` was set to Unicode translation mode. When this test is compiled with msvcrt.dll, or msvcr80.dll and later, it also sets `stderr` to Unicode transaltion mode before triggering an `assert`. Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com> Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/testcases/Makefile.am b/mingw-w64-crt/testcases/Makefile.am index b4cb67e..6cfa3f8 100644 --- a/mingw-w64-crt/testcases/Makefile.am +++ b/mingw-w64-crt/testcases/Makefile.am
@@ -187,6 +187,7 @@ t_tsearch \ t_utime \ t_vsscanf \ + t_wassert \ t_wcrtomb \ t_wcsrtombs \ t_wcstok_s \
diff --git a/mingw-w64-crt/testcases/t_wassert.c b/mingw-w64-crt/testcases/t_wassert.c new file mode 100644 index 0000000..b76a776 --- /dev/null +++ b/mingw-w64-crt/testcases/t_wassert.c
@@ -0,0 +1,85 @@ +#define _UNICODE +#include <assert.h> +#include <fcntl.h> +#include <io.h> +#include <process.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* mingw-w64 headers */ +#include "libtest.h" + +/** + * On some Windows versions, crtdll.dll, msvcrt20.dll and msvcrt40.dll may be + * redirected to system msvcrt.dll. + * + * This may result in `_setmode` succeeding to set `stderr` to Unicode + * translation mode, while `_wassert` emulation still calls `_assert`. + * + * This would result in `assert` macro silently terminating the process without + * producing any output. + * + * CRT function `_wassert` is available since msvcr80.dll, and msvcrt.dll + * since Windows Vista. Only attempt to set `stderr` to Unicode translation + * mode with msvcrt.dll, or msvcr80.dll and later. + */ +#if __MSVCRT_VERSION__ == 0x0600 || __MSVCRT_VERSION__ >= 0x0800 +#define TEST_UNICODE_MODE +#endif + +int main(int argc, char *argv[]) { + mingw_test_init (); + + if (argc != 2 || strcmp(argv[1], "assert_test") != 0) { + int exit_code; + int pipefd[2]; + int back_errfd; + intptr_t process; + ssize_t size; + char buf[512]; + + assert(_pipe(pipefd, 0, O_NOINHERIT) == 0); + + /* set stderr fd to write side of pipe, will be used by _spawnl() */ + assert((back_errfd = dup(STDERR_FILENO)) >= 0); + assert(dup2(pipefd[1], STDERR_FILENO) == 0); + assert(close(pipefd[1]) == 0); + + process = _spawnl(_P_NOWAIT, _pgmptr, argv[0], "assert_test", NULL); + + /* revert back stderr fd */ + assert(dup2(back_errfd, STDERR_FILENO) == 0); + assert(close(back_errfd) == 0); + + assert(process != -1); + + size = read(pipefd[0], buf, sizeof(buf)); + assert(size > 0); /* some data were written by child process */ + assert(strnlen(buf, sizeof(buf)) > 0); + + /* wait until child process exits */ + assert(_cwait(&exit_code, process, _WAIT_CHILD) == process); + assert(exit_code != 0); + + /* read the rest of data in the pipe and write it to stdout */ + if (size < (ssize_t)sizeof(buf)) { + size += read(pipefd[0], &buf[size], sizeof(buf) - size); + } + close(pipefd[0]); + write(STDOUT_FILENO, buf, size); + + return 0; + } + +#ifdef TEST_UNICODE_MODE + /* change stderr to translated UNICODE mode */ + _setmode(_fileno(stderr), _O_U8TEXT); +#endif + + /* call assert, it prints to stderr, parent process will check that our stderr is not empty */ + assert(0); + + /* assert(0) does not return, this process pass when returns non-zero */ + return 0; +}