[KSUSER] Improve pointer arithmetics
[reactos.git] / sdk / lib / rtl / heapdbg.c
1 /*
2 * PROJECT: ReactOS Runtime Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/rtl/heapdbg.c
5 * PURPOSE: Heap manager debug heap
6 * PROGRAMMERS: Copyright 2010 Aleksey Bragin
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <rtl.h>
12 #include <heap.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ******************************************************************/
18
19 HANDLE NTAPI
20 RtlDebugCreateHeap(ULONG Flags,
21 PVOID Addr,
22 SIZE_T ReserveSize,
23 SIZE_T CommitSize,
24 PVOID Lock,
25 PRTL_HEAP_PARAMETERS Parameters)
26 {
27 MEMORY_BASIC_INFORMATION MemoryInfo;
28 NTSTATUS Status;
29 PHEAP Heap;
30
31 /* Validate parameters */
32 if (ReserveSize <= HEAP_ENTRY_SIZE)
33 {
34 DPRINT1("HEAP: Incorrect ReserveSize %x\n", ReserveSize);
35 return NULL;
36 }
37
38 if (ReserveSize < CommitSize)
39 {
40 DPRINT1("HEAP: Incorrect CommitSize %x\n", CommitSize);
41 return NULL;
42 }
43
44 if (Flags & HEAP_NO_SERIALIZE && Lock)
45 {
46 DPRINT1("HEAP: Can't specify Lock routine and have HEAP_NO_SERIALIZE flag set\n");
47 return NULL;
48 }
49
50 /* If the address is specified, check it's virtual memory */
51 if (Addr)
52 {
53 Status = ZwQueryVirtualMemory(NtCurrentProcess(),
54 Addr,
55 MemoryBasicInformation,
56 &MemoryInfo,
57 sizeof(MemoryInfo),
58 NULL);
59
60 if (!NT_SUCCESS(Status))
61 {
62 DPRINT1("HEAP: Specified heap base address %p is invalid, Status 0x%08X\n", Addr, Status);
63 return NULL;
64 }
65
66 if (MemoryInfo.BaseAddress != Addr)
67 {
68 DPRINT1("HEAP: Specified heap base address %p is not really a base one %p\n", Addr, MemoryInfo.BaseAddress);
69 return NULL;
70 }
71
72 if (MemoryInfo.State == MEM_FREE)
73 {
74 DPRINT1("HEAP: Specified heap base address %p is free\n", Addr);
75 return NULL;
76 }
77 }
78
79 /* All validation performed, now call the real routine with skip validation check flag */
80 Flags |= HEAP_SKIP_VALIDATION_CHECKS |
81 HEAP_TAIL_CHECKING_ENABLED |
82 HEAP_FREE_CHECKING_ENABLED;
83
84 Heap = RtlCreateHeap(Flags, Addr, ReserveSize, CommitSize, Lock, Parameters);
85 if (!Heap) return NULL;
86
87 // FIXME: Capture stack backtrace
88
89 RtlpValidateHeapHeaders(Heap, TRUE);
90
91 return Heap;
92 }
93
94 BOOLEAN NTAPI
95 RtlDebugDestroyHeap(HANDLE HeapPtr)
96 {
97 SIZE_T Size = 0;
98 PHEAP Heap = (PHEAP)HeapPtr;
99
100 if (Heap == RtlGetCurrentPeb()->ProcessHeap)
101 {
102 DPRINT1("HEAP: It's forbidden delete process heap!");
103 return FALSE;
104 }
105
106 if (Heap->Signature != HEAP_SIGNATURE)
107 {
108 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
109 return FALSE;
110 }
111
112 if (!RtlpValidateHeap(Heap, FALSE)) return FALSE;
113
114 /* Make heap invalid by zeroing its signature */
115 Heap->Signature = 0;
116
117 /* Free validate headers copy if it was existing */
118 if (Heap->HeaderValidateCopy)
119 {
120 ZwFreeVirtualMemory(NtCurrentProcess(),
121 &Heap->HeaderValidateCopy,
122 &Size,
123 MEM_RELEASE);
124 }
125
126 return TRUE;
127 }
128
129 PVOID NTAPI
130 RtlDebugAllocateHeap(PVOID HeapPtr,
131 ULONG Flags,
132 SIZE_T Size)
133 {
134 PHEAP Heap = (PHEAP)HeapPtr;
135 SIZE_T AllocSize = 1;
136 BOOLEAN HeapLocked = FALSE;
137 PVOID Result;
138
139 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
140 return RtlpPageHeapAllocate(HeapPtr, Flags, Size);
141
142 if (Heap->Signature != HEAP_SIGNATURE)
143 {
144 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
145 return NULL;
146 }
147
148 /* Add settable user value flag */
149 Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS;
150
151 /* Calculate size */
152 if (Size) AllocSize = Size;
153 AllocSize = ((AllocSize + Heap->AlignRound) & Heap->AlignMask) + sizeof(HEAP_ENTRY_EXTRA);
154
155 /* Check if size didn't exceed max one */
156 if (AllocSize < Size ||
157 AllocSize > Heap->MaximumAllocationSize)
158 {
159 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size, Heap->MaximumAllocationSize);
160 return NULL;
161 }
162
163 /* Lock the heap ourselves */
164 if (!(Flags & HEAP_NO_SERIALIZE))
165 {
166 RtlEnterHeapLock(Heap->LockVariable, TRUE);
167 HeapLocked = TRUE;
168
169 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
170 Flags |= HEAP_NO_SERIALIZE;
171 }
172
173 /* Validate the heap if necessary */
174 RtlpValidateHeap(Heap, FALSE);
175
176 /* Call main routine to do the stuff */
177 Result = RtlAllocateHeap(HeapPtr, Flags, Size);
178
179 /* Validate heap headers */
180 RtlpValidateHeapHeaders(Heap, TRUE);
181
182 if (Result)
183 {
184 if (Heap->Flags & HEAP_VALIDATE_ALL_ENABLED)
185 RtlpValidateHeap(Heap, FALSE);
186 }
187
188 /* Release the lock */
189 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
190
191 return Result;
192 }
193
194 PVOID NTAPI
195 RtlDebugReAllocateHeap(HANDLE HeapPtr,
196 ULONG Flags,
197 PVOID Ptr,
198 SIZE_T Size)
199 {
200 PHEAP Heap = (PHEAP)HeapPtr;
201 SIZE_T AllocSize = 1;
202 BOOLEAN HeapLocked = FALSE;
203 PVOID Result = NULL;
204 PHEAP_ENTRY HeapEntry;
205
206 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
207 return RtlpPageHeapReAllocate(HeapPtr, Flags, Ptr, Size);
208
209 if (Heap->Signature != HEAP_SIGNATURE)
210 {
211 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
212 return NULL;
213 }
214
215 /* Add settable user value flag */
216 Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS;
217
218 /* Calculate size */
219 if (Size) AllocSize = Size;
220 AllocSize = ((AllocSize + Heap->AlignRound) & Heap->AlignMask) + sizeof(HEAP_ENTRY_EXTRA);
221
222 /* Check if size didn't exceed max one */
223 if (AllocSize < Size ||
224 AllocSize > Heap->MaximumAllocationSize)
225 {
226 DPRINT1("HEAP: Too big allocation size %x (max allowed %x)\n", Size, Heap->MaximumAllocationSize);
227 return NULL;
228 }
229
230 /* Lock the heap ourselves */
231 if (!(Flags & HEAP_NO_SERIALIZE))
232 {
233 RtlEnterHeapLock(Heap->LockVariable, TRUE);
234 HeapLocked = TRUE;
235
236 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
237 Flags |= HEAP_NO_SERIALIZE;
238 }
239
240 /* Validate the heap if necessary */
241 RtlpValidateHeap(Heap, FALSE);
242
243 /* Get the existing heap entry */
244 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
245
246 /* Validate it */
247 if (RtlpValidateHeapEntry(Heap, HeapEntry))
248 {
249 /* Call main routine to do the stuff */
250 Result = RtlReAllocateHeap(HeapPtr, Flags, Ptr, Size);
251
252 if (Result)
253 {
254 /* Validate heap headers and then heap itself */
255 RtlpValidateHeapHeaders(Heap, TRUE);
256 RtlpValidateHeap(Heap, FALSE);
257 }
258 }
259
260 /* Release the lock */
261 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
262
263 return Result;
264 }
265
266 BOOLEAN NTAPI
267 RtlDebugFreeHeap(HANDLE HeapPtr,
268 ULONG Flags,
269 PVOID Ptr)
270 {
271 PHEAP Heap = (PHEAP)HeapPtr;
272 BOOLEAN HeapLocked = FALSE;
273 PHEAP_ENTRY HeapEntry;
274 BOOLEAN Result = FALSE;
275
276 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
277 return RtlpPageHeapFree(HeapPtr, Flags, Ptr);
278
279 if (Heap->Signature != HEAP_SIGNATURE)
280 {
281 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
282 return FALSE;
283 }
284
285 /* Add skip validation flag */
286 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
287
288 /* Lock the heap ourselves */
289 if (!(Flags & HEAP_NO_SERIALIZE))
290 {
291 RtlEnterHeapLock(Heap->LockVariable, TRUE);
292 HeapLocked = TRUE;
293
294 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
295 Flags |= HEAP_NO_SERIALIZE;
296 }
297
298 /* Validate the heap if necessary */
299 RtlpValidateHeap(Heap, FALSE);
300
301 /* Get the existing heap entry */
302 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
303
304 /* Validate it */
305 if (RtlpValidateHeapEntry(Heap, HeapEntry))
306 {
307 /* If it succeeded - call the main routine */
308 Result = RtlFreeHeap(HeapPtr, Flags, Ptr);
309
310 /* Validate heap headers and then heap itself */
311 RtlpValidateHeapHeaders(Heap, TRUE);
312 RtlpValidateHeap(Heap, FALSE);
313 }
314
315 /* Release the lock */
316 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
317
318 return Result;
319 }
320
321 BOOLEAN NTAPI
322 RtlDebugGetUserInfoHeap(PVOID HeapHandle,
323 ULONG Flags,
324 PVOID BaseAddress,
325 PVOID *UserValue,
326 PULONG UserFlags)
327 {
328 PHEAP Heap = (PHEAP)HeapHandle;
329 BOOLEAN HeapLocked = FALSE;
330 PHEAP_ENTRY HeapEntry;
331 BOOLEAN Result = FALSE;
332
333 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
334 return RtlpPageHeapGetUserInfo(HeapHandle, Flags, BaseAddress, UserValue, UserFlags);
335
336 if (Heap->Signature != HEAP_SIGNATURE)
337 {
338 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
339 return FALSE;
340 }
341
342 /* Add skip validation flag */
343 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
344
345 /* Lock the heap ourselves */
346 if (!(Flags & HEAP_NO_SERIALIZE))
347 {
348 RtlEnterHeapLock(Heap->LockVariable, TRUE);
349 HeapLocked = TRUE;
350
351 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
352 Flags |= HEAP_NO_SERIALIZE;
353 }
354
355 /* Validate the heap if necessary */
356 RtlpValidateHeap(Heap, FALSE);
357
358 /* Get the existing heap entry */
359 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
360
361 /* Validate it */
362 if (RtlpValidateHeapEntry(Heap, HeapEntry))
363 {
364 /* If it succeeded - call the main routine */
365 Result = RtlGetUserInfoHeap(HeapHandle, Flags, BaseAddress, UserValue, UserFlags);
366 }
367
368 /* Release the lock */
369 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
370
371 return Result;
372 }
373
374 BOOLEAN NTAPI
375 RtlDebugSetUserValueHeap(PVOID HeapHandle,
376 ULONG Flags,
377 PVOID BaseAddress,
378 PVOID UserValue)
379 {
380 PHEAP Heap = (PHEAP)HeapHandle;
381 BOOLEAN HeapLocked = FALSE;
382 PHEAP_ENTRY HeapEntry;
383 BOOLEAN Result = FALSE;
384
385 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
386 return RtlpPageHeapSetUserValue(HeapHandle, Flags, BaseAddress, UserValue);
387
388 if (Heap->Signature != HEAP_SIGNATURE)
389 {
390 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
391 return FALSE;
392 }
393
394 /* Add skip validation flag */
395 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
396
397 /* Lock the heap ourselves */
398 if (!(Flags & HEAP_NO_SERIALIZE))
399 {
400 RtlEnterHeapLock(Heap->LockVariable, TRUE);
401 HeapLocked = TRUE;
402
403 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
404 Flags |= HEAP_NO_SERIALIZE;
405 }
406
407 /* Validate the heap if necessary */
408 RtlpValidateHeap(Heap, FALSE);
409
410 /* Get the existing heap entry */
411 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
412
413 /* Validate it */
414 if (RtlpValidateHeapEntry(Heap, HeapEntry))
415 {
416 /* If it succeeded - call the main routine */
417 Result = RtlSetUserValueHeap(HeapHandle, Flags, BaseAddress, UserValue);
418
419 /* Validate the heap */
420 RtlpValidateHeap(Heap, FALSE);
421 }
422
423 /* Release the lock */
424 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
425
426 return Result;
427 }
428
429 BOOLEAN
430 NTAPI
431 RtlDebugSetUserFlagsHeap(PVOID HeapHandle,
432 ULONG Flags,
433 PVOID BaseAddress,
434 ULONG UserFlagsReset,
435 ULONG UserFlagsSet)
436 {
437 PHEAP Heap = (PHEAP)HeapHandle;
438 BOOLEAN HeapLocked = FALSE;
439 PHEAP_ENTRY HeapEntry;
440 BOOLEAN Result = FALSE;
441
442 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
443 return RtlpPageHeapSetUserFlags(HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
444
445 /* Check if this heap allows flags to be set at all */
446 if (UserFlagsSet & ~HEAP_SETTABLE_USER_FLAGS ||
447 UserFlagsReset & ~HEAP_SETTABLE_USER_FLAGS)
448 {
449 return FALSE;
450 }
451
452 if (Heap->Signature != HEAP_SIGNATURE)
453 {
454 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
455 return FALSE;
456 }
457
458 /* Add skip validation flag */
459 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
460
461 /* Lock the heap ourselves */
462 if (!(Flags & HEAP_NO_SERIALIZE))
463 {
464 RtlEnterHeapLock(Heap->LockVariable, TRUE);
465 HeapLocked = TRUE;
466
467 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
468 Flags |= HEAP_NO_SERIALIZE;
469 }
470
471 /* Validate the heap if necessary */
472 RtlpValidateHeap(Heap, FALSE);
473
474 /* Get the existing heap entry */
475 HeapEntry = (PHEAP_ENTRY)BaseAddress - 1;
476
477 /* Validate it */
478 if (RtlpValidateHeapEntry(Heap, HeapEntry))
479 {
480 /* If it succeeded - call the main routine */
481 Result = RtlSetUserFlagsHeap(HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet);
482
483 /* Validate the heap */
484 RtlpValidateHeap(Heap, FALSE);
485 }
486
487 /* Release the lock */
488 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
489
490 return Result;
491 }
492
493 SIZE_T NTAPI
494 RtlDebugSizeHeap(HANDLE HeapPtr,
495 ULONG Flags,
496 PVOID Ptr)
497 {
498 PHEAP Heap = (PHEAP)HeapPtr;
499 BOOLEAN HeapLocked = FALSE;
500 PHEAP_ENTRY HeapEntry;
501 SIZE_T Result = ~(SIZE_T)0;
502
503 if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
504 return RtlpPageHeapSize(HeapPtr, Flags, Ptr);
505
506 /* Check heap signature */
507 if (Heap->Signature != HEAP_SIGNATURE)
508 {
509 DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature);
510 return FALSE;
511 }
512
513 /* Add skip validation flag */
514 Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
515
516 /* Lock the heap ourselves */
517 if (!(Flags & HEAP_NO_SERIALIZE))
518 {
519 RtlEnterHeapLock(Heap->LockVariable, TRUE);
520 HeapLocked = TRUE;
521
522 /* Add no serialize flag so that the main routine won't try to acquire the lock again */
523 Flags |= HEAP_NO_SERIALIZE;
524 }
525
526 /* Validate the heap if necessary */
527 RtlpValidateHeap(Heap, FALSE);
528
529 /* Get the existing heap entry */
530 HeapEntry = (PHEAP_ENTRY)Ptr - 1;
531
532 /* Validate it */
533 if (RtlpValidateHeapEntry(Heap, HeapEntry))
534 {
535 /* If it succeeded - call the main routine */
536 Result = RtlSizeHeap(HeapPtr, Flags, Ptr);
537 }
538
539 /* Release the lock */
540 if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
541
542 return Result;
543 }
544
545 /* EOF */