1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for static C++ object construction
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  *                  Mark Jansen
7  */
8 
9 #include <apitest.h>
10 #include <strsafe.h>
11 #include "dll_startup.h"
12 
13 #ifdef __GNUC__
14 #pragma GCC diagnostic ignored "-Wuninitialized"
15 #endif
16 
17 extern "C"
18 {
19 extern int static_init_counter;
20 
21 static int static_init_counter_at_startup;
22 static int static_construct_counter_at_startup;
23 static int m_uninit_at_startup;
24 
25 int static_construct_counter = 789;
26 }
27 
28 static struct init_static
29 {
30     int m_uninit;
31     int m_counter;
32 
init_staticinit_static33     init_static() :
34         m_counter(2)
35     {
36         static_init_counter_at_startup = static_init_counter;
37         static_construct_counter_at_startup = static_construct_counter;
38         m_uninit_at_startup = m_uninit;
39         static_construct_counter++;
40         m_uninit++;
41     }
42 } init_static;
43 
44 static
45 VOID
TestInitStatic(VOID)46 TestInitStatic(VOID)
47 {
48     ok(static_init_counter_at_startup == 123, "static_init_counter at startup: %d\n", static_init_counter_at_startup);
49     ok(static_construct_counter_at_startup == 789, "static_construct_counter at startup: %d\n", static_construct_counter_at_startup);
50     ok(m_uninit_at_startup == 0, "init_static.m_uninit at startup: %d\n", m_uninit_at_startup);
51 
52     ok(static_init_counter == 123, "static_init_counter: %d\n", static_init_counter);
53 
54     ok(static_construct_counter == 790, "static_construct_counter: %d\n", static_construct_counter);
55     ok(init_static.m_counter == 2, "init_static.m_counter: %d\n", init_static.m_counter);
56     ok(init_static.m_uninit == 1, "init_static.m_uninit: %d\n", init_static.m_uninit);
57 }
58 
59 static
60 VOID
TestDllStartup(VOID)61 TestDllStartup(VOID)
62 {
63 #if defined(TEST_MSVCRT)
64     const PCWSTR DllName = L"msvcrt_crt_dll_startup.dll";
65 #elif defined(TEST_STATIC_CRT)
66     const PCWSTR DllName = L"static_crt_dll_startup.dll";
67 #else
68 #error This test only makes sense for static CRT and msvcrt.dll
69 #endif
70     WCHAR DllPath[MAX_PATH];
71     GetModuleFileNameW(NULL, DllPath, _countof(DllPath));
72     wcsrchr(DllPath, L'\\')[1] = UNICODE_NULL;
73     StringCchCatW(DllPath, _countof(DllPath), DllName);
74 
75     HMODULE hDll = LoadLibraryW(DllPath);
76     if (hDll == NULL)
77     {
78         skip("Helper dll not found\n");
79         return;
80     }
81     SET_COUNTER_VALUES_POINTER *pSetCounterValuesPointer = reinterpret_cast<SET_COUNTER_VALUES_POINTER*>(GetProcAddress(hDll, "SetCounterValuesPointer"));
82     if (pSetCounterValuesPointer == NULL)
83     {
84         skip("Helper function not found\n");
85         FreeLibrary(hDll);
86         return;
87     }
88     counter_values values;
89     pSetCounterValuesPointer(&values);
90     ok(values.m_uninit_at_startup == 0, "m_uninit_at_startup = %d\n", values.m_uninit_at_startup);
91     ok(values.m_uninit == 1, "m_uninit = %d\n", values.m_uninit);
92     ok(values.m_counter == 2, "m_counter = %d\n", values.m_counter);
93     ok(values.static_construct_counter_at_startup == 5656, "static_construct_counter_at_startup = %d\n", values.static_construct_counter_at_startup);
94     ok(values.static_construct_counter == 5657, "static_construct_counter = %d\n", values.static_construct_counter);
95     ok(values.dtor_counter_at_detach == 0, "dtor_counter_at_detach = %d\n", values.dtor_counter_at_detach);
96     ok(values.dtor_counter == 0, "dtor_counter = %d\n", values.dtor_counter);
97     values.dtor_counter_at_detach = 78789;
98     values.dtor_counter = 7878;
99     FreeLibrary(hDll);
100     ok(values.m_uninit_at_startup == 0, "m_uninit_at_startup = %d\n", values.m_uninit_at_startup);
101     ok(values.m_uninit == 1, "m_uninit = %d\n", values.m_uninit);
102     ok(values.m_counter == 2, "m_counter = %d\n", values.m_counter);
103     ok(values.static_construct_counter_at_startup == 5656, "static_construct_counter_at_startup = %d\n", values.static_construct_counter_at_startup);
104     ok(values.static_construct_counter == 5657, "static_construct_counter = %d\n", values.static_construct_counter);
105     ok(values.dtor_counter_at_detach == 7878, "dtor_counter_at_detach = %d\n", values.dtor_counter_at_detach);
106     ok(values.dtor_counter == 7879, "dtor_counter = %d\n", values.dtor_counter);
107 }
108 
109 struct shared_memory
110 {
111     int init_count;
112     int uninit_count;
113 };
114 
115 static HANDLE g_FileMapping = NULL;
116 static BOOL g_CreatedFileMapping = FALSE;
117 static shared_memory* g_Memory = NULL;
118 
119 #define MAPPING_NAME L"crt_apitest_static_construct"
120 
map_memory()121 static void map_memory()
122 {
123     if (g_FileMapping)
124         return;
125 
126     g_FileMapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, MAPPING_NAME);
127     if (g_FileMapping)
128     {
129         g_CreatedFileMapping = FALSE;
130     }
131     else
132     {
133         g_FileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shared_memory), MAPPING_NAME);
134         g_CreatedFileMapping = TRUE;
135     }
136     if (g_FileMapping == NULL)
137     {
138         skip("Could not map shared memory\n");
139         return;
140     }
141     g_Memory = static_cast<shared_memory*>(MapViewOfFile(g_FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(shared_memory)));
142     if (g_Memory == NULL)
143     {
144         skip("Could not map view of shared memory\n");
145         CloseHandle(g_FileMapping);
146         g_FileMapping = NULL;
147     }
148     if (g_CreatedFileMapping)
149         ZeroMemory(g_Memory, sizeof(shared_memory));
150 }
151 
unmap_memory()152 static void unmap_memory()
153 {
154     // we do not clean the mapping in the child, since we want to count all dtor's!
155     if (g_FileMapping && g_CreatedFileMapping)
156     {
157         UnmapViewOfFile(g_Memory);
158         CloseHandle(g_FileMapping);
159         g_Memory = NULL;
160         g_FileMapping = NULL;
161     }
162 }
163 
164 static struct shared_mem_static
165 {
shared_mem_staticshared_mem_static166     shared_mem_static()
167     {
168         map_memory();
169         if (g_Memory)
170             g_Memory->init_count++;
171     }
172 
~shared_mem_staticshared_mem_static173     ~shared_mem_static()
174     {
175         if (g_Memory)
176             g_Memory->uninit_count++;
177         unmap_memory();
178     }
179 
180 } shared_mem_static;
181 
182 static
183 VOID
TestStaticDestruct(VOID)184 TestStaticDestruct(VOID)
185 {
186     ok(g_Memory != NULL, "Expected the mapping to be in place\n");
187     ok(g_CreatedFileMapping == TRUE, "Expected to create a new shared section!\n");
188     if (g_Memory == NULL)
189     {
190         skip("Can't proceed without file mapping\n");
191         return;
192     }
193     ok(g_Memory->init_count == 1, "Expected init_count to be 1, was: %d\n", g_Memory->init_count);
194     ok(g_Memory->uninit_count == 0, "Expected uninit_count to be 0, was: %d\n", g_Memory->uninit_count);
195 
196     WCHAR path[MAX_PATH];
197     // we just need an extra argument to tell the test it's only running to increment the dtor count :)
198     GetModuleFileNameW(NULL, path, _countof(path));
199     WCHAR buf[MAX_PATH+40];
200     StringCchPrintfW(buf, _countof(buf), L"\"%ls\" static_construct dummy", path);
201 
202     STARTUPINFOW si = { sizeof(si) };
203     PROCESS_INFORMATION pi;
204     BOOL created = CreateProcessW(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
205     ok(created, "Expected CreateProcess to succeed\n");
206     if (created)
207     {
208         winetest_wait_child_process(pi.hProcess);
209         CloseHandle(pi.hThread);
210         CloseHandle(pi.hProcess);
211         ok(g_Memory->init_count == 2, "Expected init_count to be 2, was: %d\n", g_Memory->init_count);
212         ok(g_Memory->uninit_count == 1, "Expected uninit_count to be 1, was: %d\n", g_Memory->uninit_count);
213     }
214 }
215 
START_TEST(static_construct)216 START_TEST(static_construct)
217 {
218     char **argv;
219     int argc = winetest_get_mainargs(&argv);
220 
221     if (argc >= 3)
222     {
223         // we are just here to increment the reference count in the shared section!
224         ok(g_Memory != NULL, "Expected the shared memory to be mapped!\n");
225         ok(g_CreatedFileMapping == FALSE, "Expected the shared memory to be created by my parent!\n");
226         return;
227     }
228 
229     TestInitStatic();
230     TestDllStartup();
231     TestStaticDestruct();
232 }
233