1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Mutant/Mutex test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 static
11 _IRQL_requires_min_(PASSIVE_LEVEL)
12 _IRQL_requires_max_(DISPATCH_LEVEL)
13 BOOLEAN
14 (NTAPI
15 *pKeAreAllApcsDisabled)(VOID);
16 
17 #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG))
18 #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER)
19 
20 C_ASSERT(sizeof(DISPATCHER_HEADER) == 8 + 2 * sizeof(PVOID));
21 C_ASSERT(sizeof(KMUTANT) == sizeof(DISPATCHER_HEADER) + 3 * sizeof(PVOID) + sizeof(PVOID));
22 C_ASSERT(sizeof(KMUTANT) == MUTANT_SIZE * sizeof(ULONG));
23 
24 #define CheckMutex(Mutex, State, New, ExpectedApcDisable) do {                  \
25     PKTHREAD Thread = KeGetCurrentThread();                                     \
26     ok_eq_uint((Mutex)->Header.Type, MutantObject);                             \
27     ok_eq_uint((Mutex)->Header.Abandoned, 0x55);                                \
28     ok_eq_uint((Mutex)->Header.Size, MUTANT_SIZE);                              \
29     ok_eq_uint((Mutex)->Header.DpcActive, 0x55);                                \
30     ok_eq_pointer((Mutex)->Header.WaitListHead.Flink,                           \
31                   &(Mutex)->Header.WaitListHead);                               \
32     ok_eq_pointer((Mutex)->Header.WaitListHead.Blink,                           \
33                   &(Mutex)->Header.WaitListHead);                               \
34     if ((State) <= 0)                                                           \
35     {                                                                           \
36         ok_eq_long((Mutex)->Header.SignalState, State);                         \
37         ok_eq_pointer((Mutex)->MutantListEntry.Flink, &Thread->MutantListHead); \
38         ok_eq_pointer((Mutex)->MutantListEntry.Blink, &Thread->MutantListHead); \
39         ok_eq_pointer(Thread->MutantListHead.Flink, &(Mutex)->MutantListEntry); \
40         ok_eq_pointer(Thread->MutantListHead.Blink, &(Mutex)->MutantListEntry); \
41         ok_eq_pointer((Mutex)->OwnerThread, Thread);                            \
42     }                                                                           \
43     else                                                                        \
44     {                                                                           \
45         ok_eq_long((Mutex)->Header.SignalState, State);                         \
46         if (New)                                                                \
47         {                                                                       \
48             ok_eq_pointer((Mutex)->MutantListEntry.Flink,                       \
49                           (PVOID)0x5555555555555555ULL);                        \
50             ok_eq_pointer((Mutex)->MutantListEntry.Blink,                       \
51                           (PVOID)0x5555555555555555ULL);                        \
52         }                                                                       \
53         ok_eq_pointer(Thread->MutantListHead.Flink, &Thread->MutantListHead);   \
54         ok_eq_pointer(Thread->MutantListHead.Blink, &Thread->MutantListHead);   \
55         ok_eq_pointer((Mutex)->OwnerThread, NULL);                              \
56     }                                                                           \
57     ok_eq_uint((Mutex)->Abandoned, 0);                                          \
58     ok_eq_uint((Mutex)->ApcDisable, ExpectedApcDisable);                        \
59 } while (0)
60 
61 #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do    \
62 {                                                                                       \
63     ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled);         \
64     ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);                            \
65     if (pKeAreAllApcsDisabled)                                                          \
66         ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled);                           \
67     ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);                          \
68     ok_irql(Irql);                                                                      \
69 } while (0)
70 
71 static
72 VOID
TestMutant(VOID)73 TestMutant(VOID)
74 {
75     NTSTATUS Status;
76     KMUTANT Mutant;
77     LONG State;
78     LONG i;
79     PKTHREAD Thread = KeGetCurrentThread();
80 
81     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
82     RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
83     KeInitializeMutant(&Mutant, FALSE);
84     CheckMutex(&Mutant, 1L, TRUE, 0);
85     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
86 
87     RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
88     KeInitializeMutant(&Mutant, TRUE);
89     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
90     CheckMutex(&Mutant, 0L, TRUE, 0);
91     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
92     ok_eq_long(State, 0L);
93     CheckMutex(&Mutant, 1L, FALSE, 0);
94     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
95 
96     /* Acquire and release */
97     Status = KeWaitForSingleObject(&Mutant,
98                                    Executive,
99                                    KernelMode,
100                                    FALSE,
101                                    NULL);
102     ok_eq_hex(Status, STATUS_SUCCESS);
103     CheckMutex(&Mutant, 0L, TRUE, 0);
104     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
105 
106     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
107     ok_eq_long(State, 0L);
108     CheckMutex(&Mutant, 1L, FALSE, 0);
109     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
110 
111     /* Acquire recursively */
112     for (i = 0; i < 8; i++)
113     {
114         KmtStartSeh()
115             Status = KeWaitForSingleObject(&Mutant,
116                                            Executive,
117                                            KernelMode,
118                                            FALSE,
119                                            NULL);
120         KmtEndSeh(STATUS_SUCCESS);
121         ok_eq_hex(Status, STATUS_SUCCESS);
122         CheckMutex(&Mutant, -i, FALSE, 0);
123         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
124     }
125 
126     for (i = 0; i < 7; i++)
127     {
128         KmtStartSeh()
129             State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
130         KmtEndSeh(STATUS_SUCCESS);
131         ok_eq_long(State, -7L + i);
132         CheckMutex(&Mutant, -6L + i, FALSE, 0);
133         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
134     }
135 
136     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
137     ok_eq_long(State, 0L);
138     CheckMutex(&Mutant, 1L, FALSE, 0);
139     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
140 
141     /* Pretend to acquire it recursively -MINLONG times */
142     KmtStartSeh()
143         Status = KeWaitForSingleObject(&Mutant,
144                                        Executive,
145                                        KernelMode,
146                                        FALSE,
147                                        NULL);
148     KmtEndSeh(STATUS_SUCCESS);
149     ok_eq_hex(Status, STATUS_SUCCESS);
150     CheckMutex(&Mutant, 0L, FALSE, 0);
151     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
152 
153     Mutant.Header.SignalState = MINLONG + 1;
154     KmtStartSeh()
155         Status = KeWaitForSingleObject(&Mutant,
156                                        Executive,
157                                        KernelMode,
158                                        FALSE,
159                                        NULL);
160     KmtEndSeh(STATUS_SUCCESS);
161     ok_eq_hex(Status, STATUS_SUCCESS);
162     CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0);
163     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
164 
165     KmtStartSeh()
166         KeWaitForSingleObject(&Mutant,
167                               Executive,
168                               KernelMode,
169                               FALSE,
170                               NULL);
171     KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED);
172     CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0);
173     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
174 
175     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
176     ok_eq_long(State, (LONG)MINLONG);
177     CheckMutex(&Mutant, (LONG)MINLONG + 1L, FALSE, 0);
178     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
179 
180     Mutant.Header.SignalState = -1;
181     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
182     ok_eq_long(State, -1L);
183     CheckMutex(&Mutant, 0L, FALSE, 0);
184     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
185 
186     State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
187     ok_eq_long(State, 0L);
188     CheckMutex(&Mutant, 1L, FALSE, 0);
189     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
190 
191     /* Now release it once too often */
192     KmtStartSeh()
193         KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
194     KmtEndSeh(STATUS_MUTANT_NOT_OWNED);
195     CheckMutex(&Mutant, 1L, FALSE, 0);
196     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
197 }
198 
199 static
200 VOID
TestMutex(VOID)201 TestMutex(VOID)
202 {
203     NTSTATUS Status;
204     KMUTEX Mutex;
205     LONG State;
206     LONG i;
207     PKTHREAD Thread = KeGetCurrentThread();
208 
209     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
210     RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
211     KeInitializeMutex(&Mutex, 0);
212     CheckMutex(&Mutex, 1L, TRUE, 1);
213     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
214 
215     RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
216     KeInitializeMutex(&Mutex, 123);
217     CheckMutex(&Mutex, 1L, TRUE, 1);
218     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
219 
220     /* Acquire and release */
221     Status = KeWaitForSingleObject(&Mutex,
222                                    Executive,
223                                    KernelMode,
224                                    FALSE,
225                                    NULL);
226     ok_eq_hex(Status, STATUS_SUCCESS);
227     CheckMutex(&Mutex, 0L, FALSE, 1);
228     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
229 
230     State = KeReleaseMutex(&Mutex, FALSE);
231     ok_eq_long(State, 0L);
232     CheckMutex(&Mutex, 1L, FALSE, 1);
233     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
234 
235     /* Acquire recursively */
236     for (i = 0; i < 8; i++)
237     {
238         KmtStartSeh()
239             Status = KeWaitForSingleObject(&Mutex,
240                                            Executive,
241                                            KernelMode,
242                                            FALSE,
243                                            NULL);
244         KmtEndSeh(STATUS_SUCCESS);
245         ok_eq_hex(Status, STATUS_SUCCESS);
246         CheckMutex(&Mutex, -i, FALSE, 1);
247         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
248     }
249 
250     for (i = 0; i < 7; i++)
251     {
252         KmtStartSeh()
253             State = KeReleaseMutex(&Mutex, FALSE);
254         KmtEndSeh(STATUS_SUCCESS);
255         ok_eq_long(State, -7L + i);
256         CheckMutex(&Mutex, -6L + i, FALSE, 1);
257         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
258     }
259 
260     State = KeReleaseMutex(&Mutex, FALSE);
261     ok_eq_long(State, 0L);
262     CheckMutex(&Mutex, 1L, FALSE, 1);
263     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
264 
265     /* Pretend to acquire it recursively -MINLONG times */
266     KmtStartSeh()
267         Status = KeWaitForSingleObject(&Mutex,
268                                        Executive,
269                                        KernelMode,
270                                        FALSE,
271                                        NULL);
272     KmtEndSeh(STATUS_SUCCESS);
273     ok_eq_hex(Status, STATUS_SUCCESS);
274     CheckMutex(&Mutex, 0L, FALSE, 1);
275     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
276 
277     Mutex.Header.SignalState = MINLONG + 1;
278     KmtStartSeh()
279         Status = KeWaitForSingleObject(&Mutex,
280                                        Executive,
281                                        KernelMode,
282                                        FALSE,
283                                        NULL);
284     KmtEndSeh(STATUS_SUCCESS);
285     ok_eq_hex(Status, STATUS_SUCCESS);
286     CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1);
287     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
288 
289     KmtStartSeh()
290         KeWaitForSingleObject(&Mutex,
291                               Executive,
292                               KernelMode,
293                               FALSE,
294                               NULL);
295     KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED);
296     CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1);
297     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
298 
299     State = KeReleaseMutex(&Mutex, FALSE);
300     ok_eq_long(State, (LONG)MINLONG);
301     CheckMutex(&Mutex, (LONG)MINLONG + 1L, FALSE, 1);
302     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
303 
304     Mutex.Header.SignalState = -1;
305     State = KeReleaseMutex(&Mutex, FALSE);
306     ok_eq_long(State, -1L);
307     CheckMutex(&Mutex, 0L, FALSE, 1);
308     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
309 
310     State = KeReleaseMutex(&Mutex, FALSE);
311     ok_eq_long(State, 0L);
312     CheckMutex(&Mutex, 1L, FALSE, 1);
313     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
314 
315     /* Now release it once too often */
316     KmtStartSeh()
317         KeReleaseMutex(&Mutex, FALSE);
318     KmtEndSeh(STATUS_MUTANT_NOT_OWNED);
319     CheckMutex(&Mutex, 1L, FALSE, 1);
320     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
321 }
322 
START_TEST(KeMutex)323 START_TEST(KeMutex)
324 {
325     pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
326     if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
327     {
328         /* We can live without this function here */
329     }
330 
331     TestMutant();
332     TestMutex();
333 }
334