1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Test for NtFreeVirtualMemory
5  * COPYRIGHT:   Copyright 2011 Jérôme Gardou <jerome.gardou@reactos.org>
6  *              Copyright 2017 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
7  */
8 
9 #include "precomp.h"
10 
11 static void Test_NtFreeVirtualMemory(void)
12 {
13     PVOID Buffer = NULL, Buffer2;
14     SIZE_T Length = PAGE_SIZE;
15     NTSTATUS Status;
16 
17     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
18                                      &Buffer,
19                                      0,
20                                      &Length,
21                                      MEM_RESERVE,
22                                      PAGE_READWRITE);
23     ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed : 0x%08lx\n", Status);
24     ok(Length == PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
25     ok(((ULONG_PTR)Buffer % PAGE_SIZE) == 0, "The buffer is not aligned to PAGE_SIZE.\n");
26 
27     Status = NtFreeVirtualMemory(NtCurrentProcess(),
28                                  &Buffer,
29                                  &Length,
30                                  MEM_DECOMMIT);
31     ok(Status == STATUS_SUCCESS, "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
32 
33     /* Now try to free more than we got */
34     Length++;
35     Status = NtFreeVirtualMemory(NtCurrentProcess(),
36                                  &Buffer,
37                                  &Length,
38                                  MEM_DECOMMIT);
39     ok(Status == STATUS_UNABLE_TO_FREE_VM, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
40 
41     Status = NtFreeVirtualMemory(NtCurrentProcess(),
42                                  &Buffer,
43                                  &Length,
44                                  MEM_RELEASE);
45     ok(Status == STATUS_UNABLE_TO_FREE_VM, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
46 
47     /* Free out of bounds from the wrong origin */
48     Length = PAGE_SIZE;
49     Buffer2 = (PVOID)((ULONG_PTR)Buffer+1);
50 
51     Status = NtFreeVirtualMemory(NtCurrentProcess(),
52                                  &Buffer2,
53                                  &Length,
54                                  MEM_DECOMMIT);
55     ok(Status == STATUS_UNABLE_TO_FREE_VM, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
56 
57     Buffer2 = (PVOID)((ULONG_PTR)Buffer+1);
58     Length = PAGE_SIZE;
59     Status = NtFreeVirtualMemory(NtCurrentProcess(),
60                                  &Buffer2,
61                                  &Length,
62                                  MEM_RELEASE);
63     ok(Status == STATUS_UNABLE_TO_FREE_VM, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
64 
65     /* Same but in bounds */
66     Length = PAGE_SIZE - 1;
67     Buffer2 = (PVOID)((ULONG_PTR)Buffer+1);
68 
69     Status = NtFreeVirtualMemory(NtCurrentProcess(),
70                                  &Buffer2,
71                                  &Length,
72                                  MEM_DECOMMIT);
73     ok(Status == STATUS_SUCCESS, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
74     ok(Buffer2 == Buffer, "NtFreeVirtualMemory set wrong buffer.\n");
75     ok(Length == PAGE_SIZE, "NtFreeVirtualMemory did not round Length to PAGE_SIZE.\n");
76 
77     Buffer2 = (PVOID)((ULONG_PTR)Buffer+1);
78     Length = PAGE_SIZE-1;
79     Status = NtFreeVirtualMemory(NtCurrentProcess(),
80                                  &Buffer2,
81                                  &Length,
82                                  MEM_RELEASE);
83     ok(Status == STATUS_SUCCESS, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
84     ok(Buffer2 == Buffer, "NtFreeVirtualMemory set wrong buffer.\n");
85     ok(Length == PAGE_SIZE, "NtFreeVirtualMemory did not round Length to PAGE_SIZE.\n");
86 
87     /* Now allocate two pages and try to free them one after the other */
88     Length = 2*PAGE_SIZE;
89     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
90                                      &Buffer,
91                                      0,
92                                      &Length,
93                                      MEM_RESERVE,
94                                      PAGE_READWRITE);
95     ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed : 0x%08lx\n", Status);
96     ok(Length == 2*PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
97     ok(((ULONG_PTR)Buffer % PAGE_SIZE) == 0, "The buffer is not aligned to PAGE_SIZE.\n");
98 
99     Buffer2 = Buffer;
100     Length = PAGE_SIZE;
101     Status = NtFreeVirtualMemory(NtCurrentProcess(),
102                                  &Buffer2,
103                                  &Length,
104                                  MEM_RELEASE);
105     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
106     ok(Length == PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
107     ok(Buffer2 == Buffer, "The buffer is not aligned to PAGE_SIZE.\n");
108 
109     Buffer2 = (PVOID)((ULONG_PTR)Buffer+PAGE_SIZE);
110     Length = PAGE_SIZE;
111     Status = NtFreeVirtualMemory(NtCurrentProcess(),
112                                  &Buffer2,
113                                  &Length,
114                                  MEM_RELEASE);
115     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
116     ok(Length == PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
117     ok(Buffer2 == (PVOID)((ULONG_PTR)Buffer+PAGE_SIZE), "The buffer is not aligned to PAGE_SIZE.\n");
118 
119     /* Same, but try to free the second page before the first one */
120     Length = 2*PAGE_SIZE;
121     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
122                                      &Buffer,
123                                      0,
124                                      &Length,
125                                      MEM_RESERVE,
126                                      PAGE_READWRITE);
127     ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed : 0x%08lx\n", Status);
128     ok(Length == 2*PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
129     ok(((ULONG_PTR)Buffer % PAGE_SIZE) == 0, "The buffer is not aligned to PAGE_SIZE.\n");
130 
131     Buffer2 = (PVOID)((ULONG_PTR)Buffer+PAGE_SIZE);
132     Length = PAGE_SIZE;
133     Status = NtFreeVirtualMemory(NtCurrentProcess(),
134                                  &Buffer2,
135                                  &Length,
136                                  MEM_RELEASE);
137     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
138     ok(Length == PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
139     ok(Buffer2 == (PVOID)((ULONG_PTR)Buffer+PAGE_SIZE), "The buffer is not aligned to PAGE_SIZE.\n");
140 
141     Buffer2 = Buffer;
142     Length = PAGE_SIZE;
143     Status = NtFreeVirtualMemory(NtCurrentProcess(),
144                                  &Buffer2,
145                                  &Length,
146                                  MEM_RELEASE);
147     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
148     ok(Length == PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
149     ok(Buffer2 == Buffer, "The buffer is not aligned to PAGE_SIZE.\n");
150 
151     /* Now allocate two pages and try to free them in the middle */
152     Length = 2*PAGE_SIZE;
153     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
154                                      &Buffer,
155                                      0,
156                                      &Length,
157                                      MEM_RESERVE,
158                                      PAGE_READWRITE);
159     ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed : 0x%08lx\n", Status);
160     ok(Length == 2*PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
161     ok(((ULONG_PTR)Buffer % PAGE_SIZE) == 0, "The buffer is not aligned to PAGE_SIZE.\n");
162 
163     Buffer2 = (PVOID)((ULONG_PTR)Buffer+1);
164     Length = PAGE_SIZE;
165     Status = NtFreeVirtualMemory(NtCurrentProcess(),
166                                  &Buffer2,
167                                  &Length,
168                                  MEM_RELEASE);
169     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed : 0x%08lx\n", Status);
170     ok(Length == 2*PAGE_SIZE, "Length mismatch : 0x%08lx\n", (ULONG)Length);
171     ok(Buffer2 == Buffer, "The buffer is not aligned to PAGE_SIZE.\n");
172 }
173 
174 static void Test_NtFreeVirtualMemory_Parameters(void)
175 {
176     NTSTATUS Status;
177     ULONG FreeType;
178     int i;
179 
180     // 4th parameter: "ULONG FreeType".
181 
182     // A type is mandatory.
183     Status = NtFreeVirtualMemory(NULL, NULL, NULL, 0ul);
184     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
185 
186     // All but MEM_DECOMMIT and MEM_RELEASE are unsupported.
187     // Each bit one by one.
188     for (i = 0; i < 32; ++i)
189     {
190         FreeType = 1 << i;
191         if (FreeType == MEM_DECOMMIT || FreeType == MEM_RELEASE)
192             continue;
193 
194         Status = NtFreeVirtualMemory(NULL, NULL, NULL, FreeType);
195         ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
196     }
197     // All bits at once.
198     // Not testing all other values.
199     Status = NtFreeVirtualMemory(NULL, NULL, NULL, ~(MEM_DECOMMIT | MEM_RELEASE));
200     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
201     Status = NtFreeVirtualMemory(NULL, NULL, NULL, ~MEM_DECOMMIT);
202     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
203     Status = NtFreeVirtualMemory(NULL, NULL, NULL, ~MEM_RELEASE);
204     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
205     Status = NtFreeVirtualMemory(NULL, NULL, NULL, ~0ul);
206     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
207 
208     // MEM_DECOMMIT and MEM_RELEASE are exclusive.
209     Status = NtFreeVirtualMemory(NULL, NULL, NULL, MEM_DECOMMIT | MEM_RELEASE);
210     ok(Status == STATUS_INVALID_PARAMETER_4, "NtFreeVirtualMemory returned status : 0x%08lx\n", Status);
211 }
212 
213 START_TEST(NtFreeVirtualMemory)
214 {
215     Test_NtFreeVirtualMemory();
216     Test_NtFreeVirtualMemory_Parameters();
217 }