Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
b0f58617
Commit
b0f58617
authored
Dec 19, 2001
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved heap functions to ntdll.
Got rid of internal heap flags. Reimplemented MapLS to not depend on the segptr heap.
parent
024d39fc
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1665 additions
and
1659 deletions
+1665
-1659
kernel32.spec
dlls/kernel/kernel32.spec
+4
-4
Makefile.in
dlls/ntdll/Makefile.in
+1
-0
debugtools.c
dlls/ntdll/debugtools.c
+3
-2
heap.c
dlls/ntdll/heap.c
+1424
-0
ntdll.spec
dlls/ntdll/ntdll.spec
+8
-8
rtl.c
dlls/ntdll/rtl.c
+0
-58
ifs.c
dlls/ole32/ifs.c
+17
-10
font.c
graphics/win16drv/font.c
+1
-1
heap.h
include/heap.h
+5
-7
ntddk.h
include/ntddk.h
+1
-0
winbase.h
include/winbase.h
+23
-14
winnt.h
include/winnt.h
+1
-5
heap.c
memory/heap.c
+99
-1550
selector.c
memory/selector.c
+78
-0
No files found.
dlls/kernel/kernel32.spec
View file @
b0f58617
...
...
@@ -500,15 +500,15 @@ debug_channels (comm debugstr dll int resource stress thunk toolhelp win32)
@ stub Heap32ListFirst
@ stub Heap32ListNext
@ stub Heap32Next
@
stdcall HeapAlloc(long long long) HeapAlloc
@
forward HeapAlloc ntdll.RtlAllocateHeap
@ stdcall HeapCompact(long long) HeapCompact
@ stdcall HeapCreate(long long long) HeapCreate
@ stdcall HeapDestroy(long) HeapDestroy
@
stdcall HeapFree(long long ptr) HeapFree
@
forward HeapFree ntdll.RtlFreeHeap
@ stdcall HeapLock(long) HeapLock
@
stdcall HeapReAlloc(long long ptr long) HeapReAlloc
@
forward HeapReAlloc ntdll.RtlReAllocateHeap
@ stub HeapSetFlags
@
stdcall HeapSize(long long ptr) HeapSize
@
forward HeapSize ntdll.RtlSizeHeap
@ stdcall HeapUnlock(long) HeapUnlock
@ stdcall HeapValidate(long long ptr) HeapValidate
@ stdcall HeapWalk(long ptr) HeapWalk
...
...
dlls/ntdll/Makefile.in
View file @
b0f58617
...
...
@@ -11,6 +11,7 @@ C_SRCS = \
exception.c
\
error.c
\
file.c
\
heap.c
\
large_int.c
\
misc.c
\
nt.c
\
...
...
dlls/ntdll/debugtools.c
View file @
b0f58617
...
...
@@ -14,6 +14,7 @@
#include "thread.h"
#include "winbase.h"
#include "winnt.h"
#include "ntddk.h"
#include "wtypes.h"
DECLARE_DEBUG_CHANNEL
(
tid
);
...
...
@@ -50,9 +51,9 @@ static inline struct debug_info *get_info(void)
tmp
.
out_pos
=
tmp
.
output
;
}
if
(
!
GetProcessHeap
())
return
&
tmp
;
/* setup the temp structure in case
HeapAlloc
wants to print something */
/* setup the temp structure in case
RtlAllocateHeap
wants to print something */
NtCurrentTeb
()
->
debug_info
=
&
tmp
;
info
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
info
)
);
info
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
sizeof
(
*
info
)
);
info
->
str_pos
=
info
->
strings
;
info
->
out_pos
=
info
->
output
;
NtCurrentTeb
()
->
debug_info
=
info
;
...
...
dlls/ntdll/heap.c
0 → 100644
View file @
b0f58617
/*
* Win32 heap functions
*
* Copyright 1996 Alexandre Julliard
* Copyright 1998 Ulrich Weigand
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ntddk.h"
#include "wine/winbase16.h"
#include "winbase.h"
#include "winerror.h"
#include "winnt.h"
#include "heap.h"
#include "thread.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL
(
heap
);
/* Note: the heap data structures are based on what Pietrek describes in his
* book 'Windows 95 System Programming Secrets'. The layout is not exactly
* the same, but could be easily adapted if it turns out some programs
* require it.
*/
typedef
struct
tagARENA_INUSE
{
DWORD
size
;
/* Block size; must be the first field */
DWORD
magic
;
/* Magic number */
}
ARENA_INUSE
;
typedef
struct
tagARENA_FREE
{
DWORD
size
;
/* Block size; must be the first field */
DWORD
magic
;
/* Magic number */
struct
tagARENA_FREE
*
next
;
/* Next free arena */
struct
tagARENA_FREE
*
prev
;
/* Prev free arena */
}
ARENA_FREE
;
#define ARENA_FLAG_FREE 0x00000001
/* flags OR'ed with arena size */
#define ARENA_FLAG_PREV_FREE 0x00000002
#define ARENA_SIZE_MASK (~3)
#define ARENA_INUSE_MAGIC 0x44455355
/* Value for arena 'magic' field */
#define ARENA_FREE_MAGIC 0x45455246
/* Value for arena 'magic' field */
#define ARENA_INUSE_FILLER 0x55
#define ARENA_FREE_FILLER 0xaa
#define QUIET 1
/* Suppress messages */
#define NOISY 0
/* Report all errors */
#define HEAP_NB_FREE_LISTS 4
/* Number of free lists */
/* Max size of the blocks on the free lists */
static
const
DWORD
HEAP_freeListSizes
[
HEAP_NB_FREE_LISTS
]
=
{
0x20
,
0x80
,
0x200
,
~
0UL
};
typedef
struct
{
DWORD
size
;
ARENA_FREE
arena
;
}
FREE_LIST_ENTRY
;
struct
tagHEAP
;
typedef
struct
tagSUBHEAP
{
DWORD
size
;
/* Size of the whole sub-heap */
DWORD
commitSize
;
/* Committed size of the sub-heap */
DWORD
headerSize
;
/* Size of the heap header */
struct
tagSUBHEAP
*
next
;
/* Next sub-heap */
struct
tagHEAP
*
heap
;
/* Main heap structure */
DWORD
magic
;
/* Magic number */
}
SUBHEAP
;
#define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
typedef
struct
tagHEAP
{
SUBHEAP
subheap
;
/* First sub-heap */
struct
tagHEAP
*
next
;
/* Next heap for this process */
CRITICAL_SECTION
critSection
;
/* Critical section for serialization */
FREE_LIST_ENTRY
freeList
[
HEAP_NB_FREE_LISTS
];
/* Free lists */
DWORD
flags
;
/* Heap flags */
DWORD
magic
;
/* Magic number */
}
HEAP
;
#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
#define HEAP_DEF_SIZE 0x110000
/* Default heap size = 1Mb + 64Kb */
#define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE))
/* Min. heap block size */
#define COMMIT_MASK 0xffff
/* bitmask for commit/decommit granularity */
static
HANDLE
processHeap
;
/* main process heap */
static
HEAP
*
firstHeap
;
/* head of secondary heaps list */
static
BOOL
HEAP_IsRealArena
(
HEAP
*
heapPtr
,
DWORD
flags
,
LPCVOID
block
,
BOOL
quiet
);
/* SetLastError for ntdll */
inline
static
void
set_status
(
NTSTATUS
status
)
{
#if defined(__i386__) && defined(__GNUC__)
/* in this case SetLastError is an inline function so we can use it */
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
#else
/* cannot use SetLastError, do it manually */
NtCurrentTeb
()
->
last_error
=
RtlNtStatusToDosError
(
status
);
#endif
}
/* set the process main heap */
static
void
set_process_heap
(
HANDLE
heap
)
{
HANDLE
*
pdb
=
(
HANDLE
*
)
NtCurrentTeb
()
->
process
;
pdb
[
0x18
/
sizeof
(
HANDLE
)]
=
heap
;
/* heap is at offset 0x18 in pdb */
processHeap
=
heap
;
}
/***********************************************************************
* HEAP_Dump
*/
void
HEAP_Dump
(
HEAP
*
heap
)
{
int
i
;
SUBHEAP
*
subheap
;
char
*
ptr
;
DPRINTF
(
"Heap: %08lx
\n
"
,
(
DWORD
)
heap
);
DPRINTF
(
"Next: %08lx Sub-heaps: %08lx"
,
(
DWORD
)
heap
->
next
,
(
DWORD
)
&
heap
->
subheap
);
subheap
=
&
heap
->
subheap
;
while
(
subheap
->
next
)
{
DPRINTF
(
" -> %08lx"
,
(
DWORD
)
subheap
->
next
);
subheap
=
subheap
->
next
;
}
DPRINTF
(
"
\n
Free lists:
\n
Block Stat Size Id
\n
"
);
for
(
i
=
0
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
)
DPRINTF
(
"%08lx free %08lx prev=%08lx next=%08lx
\n
"
,
(
DWORD
)
&
heap
->
freeList
[
i
].
arena
,
heap
->
freeList
[
i
].
arena
.
size
,
(
DWORD
)
heap
->
freeList
[
i
].
arena
.
prev
,
(
DWORD
)
heap
->
freeList
[
i
].
arena
.
next
);
subheap
=
&
heap
->
subheap
;
while
(
subheap
)
{
DWORD
freeSize
=
0
,
usedSize
=
0
,
arenaSize
=
subheap
->
headerSize
;
DPRINTF
(
"
\n\n
Sub-heap %08lx: size=%08lx committed=%08lx
\n
"
,
(
DWORD
)
subheap
,
subheap
->
size
,
subheap
->
commitSize
);
DPRINTF
(
"
\n
Block Stat Size Id
\n
"
);
ptr
=
(
char
*
)
subheap
+
subheap
->
headerSize
;
while
(
ptr
<
(
char
*
)
subheap
+
subheap
->
size
)
{
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
ARENA_FREE
*
pArena
=
(
ARENA_FREE
*
)
ptr
;
DPRINTF
(
"%08lx free %08lx prev=%08lx next=%08lx
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
->
next
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_FREE
);
freeSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
else
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_PREV_FREE
)
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DPRINTF
(
"%08lx Used %08lx back=%08lx
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
,
*
((
DWORD
*
)
pArena
-
1
)
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_INUSE
);
usedSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DPRINTF
(
"%08lx used %08lx
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_INUSE
);
usedSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
}
DPRINTF
(
"
\n
Total: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)
\n\n
"
,
subheap
->
size
,
subheap
->
commitSize
,
freeSize
,
usedSize
,
arenaSize
,
(
arenaSize
*
100
)
/
subheap
->
size
);
subheap
=
subheap
->
next
;
}
}
/***********************************************************************
* HEAP_GetPtr
* RETURNS
* Pointer to the heap
* NULL: Failure
*/
static
HEAP
*
HEAP_GetPtr
(
HANDLE
heap
/* [in] Handle to the heap */
)
{
HEAP
*
heapPtr
=
(
HEAP
*
)
heap
;
if
(
!
heapPtr
||
(
heapPtr
->
magic
!=
HEAP_MAGIC
))
{
ERR
(
"Invalid heap %08x!
\n
"
,
heap
);
return
NULL
;
}
if
(
TRACE_ON
(
heap
)
&&
!
HEAP_IsRealArena
(
heapPtr
,
0
,
NULL
,
NOISY
))
{
HEAP_Dump
(
heapPtr
);
assert
(
FALSE
);
return
NULL
;
}
return
heapPtr
;
}
/***********************************************************************
* HEAP_InsertFreeBlock
*
* Insert a free block into the free list.
*/
static
void
HEAP_InsertFreeBlock
(
HEAP
*
heap
,
ARENA_FREE
*
pArena
)
{
FREE_LIST_ENTRY
*
pEntry
=
heap
->
freeList
;
while
(
pEntry
->
size
<
pArena
->
size
)
pEntry
++
;
pArena
->
size
|=
ARENA_FLAG_FREE
;
pArena
->
next
=
pEntry
->
arena
.
next
;
pArena
->
next
->
prev
=
pArena
;
pArena
->
prev
=
&
pEntry
->
arena
;
pEntry
->
arena
.
next
=
pArena
;
}
/***********************************************************************
* HEAP_FindSubHeap
* Find the sub-heap containing a given address.
*
* RETURNS
* Pointer: Success
* NULL: Failure
*/
static
SUBHEAP
*
HEAP_FindSubHeap
(
HEAP
*
heap
,
/* [in] Heap pointer */
LPCVOID
ptr
/* [in] Address */
)
{
SUBHEAP
*
sub
=
&
heap
->
subheap
;
while
(
sub
)
{
if
(((
char
*
)
ptr
>=
(
char
*
)
sub
)
&&
((
char
*
)
ptr
<
(
char
*
)
sub
+
sub
->
size
))
return
sub
;
sub
=
sub
->
next
;
}
return
NULL
;
}
/***********************************************************************
* HEAP_Commit
*
* Make sure the heap storage is committed up to (not including) ptr.
*/
static
inline
BOOL
HEAP_Commit
(
SUBHEAP
*
subheap
,
void
*
ptr
)
{
DWORD
size
=
(
DWORD
)((
char
*
)
ptr
-
(
char
*
)
subheap
);
size
=
(
size
+
COMMIT_MASK
)
&
~
COMMIT_MASK
;
if
(
size
>
subheap
->
size
)
size
=
subheap
->
size
;
if
(
size
<=
subheap
->
commitSize
)
return
TRUE
;
if
(
!
VirtualAlloc
(
(
char
*
)
subheap
+
subheap
->
commitSize
,
size
-
subheap
->
commitSize
,
MEM_COMMIT
,
PAGE_EXECUTE_READWRITE
))
{
WARN
(
"Could not commit %08lx bytes at %08lx for heap %08lx
\n
"
,
size
-
subheap
->
commitSize
,
(
DWORD
)((
char
*
)
subheap
+
subheap
->
commitSize
),
(
DWORD
)
subheap
->
heap
);
return
FALSE
;
}
subheap
->
commitSize
=
size
;
return
TRUE
;
}
/***********************************************************************
* HEAP_Decommit
*
* If possible, decommit the heap storage from (including) 'ptr'.
*/
static
inline
BOOL
HEAP_Decommit
(
SUBHEAP
*
subheap
,
void
*
ptr
)
{
DWORD
size
=
(
DWORD
)((
char
*
)
ptr
-
(
char
*
)
subheap
);
/* round to next block and add one full block */
size
=
((
size
+
COMMIT_MASK
)
&
~
COMMIT_MASK
)
+
COMMIT_MASK
+
1
;
if
(
size
>=
subheap
->
commitSize
)
return
TRUE
;
if
(
!
VirtualFree
(
(
char
*
)
subheap
+
size
,
subheap
->
commitSize
-
size
,
MEM_DECOMMIT
))
{
WARN
(
"Could not decommit %08lx bytes at %08lx for heap %08lx
\n
"
,
subheap
->
commitSize
-
size
,
(
DWORD
)((
char
*
)
subheap
+
size
),
(
DWORD
)
subheap
->
heap
);
return
FALSE
;
}
subheap
->
commitSize
=
size
;
return
TRUE
;
}
/***********************************************************************
* HEAP_CreateFreeBlock
*
* Create a free block at a specified address. 'size' is the size of the
* whole block, including the new arena.
*/
static
void
HEAP_CreateFreeBlock
(
SUBHEAP
*
subheap
,
void
*
ptr
,
DWORD
size
)
{
ARENA_FREE
*
pFree
;
/* Create a free arena */
pFree
=
(
ARENA_FREE
*
)
ptr
;
pFree
->
magic
=
ARENA_FREE_MAGIC
;
/* If debugging, erase the freed block content */
if
(
TRACE_ON
(
heap
))
{
char
*
pEnd
=
(
char
*
)
ptr
+
size
;
if
(
pEnd
>
(
char
*
)
subheap
+
subheap
->
commitSize
)
pEnd
=
(
char
*
)
subheap
+
subheap
->
commitSize
;
if
(
pEnd
>
(
char
*
)(
pFree
+
1
))
memset
(
pFree
+
1
,
ARENA_FREE_FILLER
,
pEnd
-
(
char
*
)(
pFree
+
1
)
);
}
/* Check if next block is free also */
if
(((
char
*
)
ptr
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
&&
(
*
(
DWORD
*
)((
char
*
)
ptr
+
size
)
&
ARENA_FLAG_FREE
))
{
/* Remove the next arena from the free list */
ARENA_FREE
*
pNext
=
(
ARENA_FREE
*
)((
char
*
)
ptr
+
size
);
pNext
->
next
->
prev
=
pNext
->
prev
;
pNext
->
prev
->
next
=
pNext
->
next
;
size
+=
(
pNext
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pNext
);
if
(
TRACE_ON
(
heap
))
memset
(
pNext
,
ARENA_FREE_FILLER
,
sizeof
(
ARENA_FREE
)
);
}
/* Set the next block PREV_FREE flag and pointer */
if
((
char
*
)
ptr
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
{
DWORD
*
pNext
=
(
DWORD
*
)((
char
*
)
ptr
+
size
);
*
pNext
|=
ARENA_FLAG_PREV_FREE
;
*
(
ARENA_FREE
**
)(
pNext
-
1
)
=
pFree
;
}
/* Last, insert the new block into the free list */
pFree
->
size
=
size
-
sizeof
(
*
pFree
);
HEAP_InsertFreeBlock
(
subheap
->
heap
,
pFree
);
}
/***********************************************************************
* HEAP_MakeInUseBlockFree
*
* Turn an in-use block into a free block. Can also decommit the end of
* the heap, and possibly even free the sub-heap altogether.
*/
static
void
HEAP_MakeInUseBlockFree
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
)
{
ARENA_FREE
*
pFree
;
DWORD
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pArena
);
/* Check if we can merge with previous block */
if
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
)
{
pFree
=
*
((
ARENA_FREE
**
)
pArena
-
1
);
size
+=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
);
/* Remove it from the free list */
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
}
else
pFree
=
(
ARENA_FREE
*
)
pArena
;
/* Create a free block */
HEAP_CreateFreeBlock
(
subheap
,
pFree
,
size
);
size
=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
);
if
((
char
*
)
pFree
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
return
;
/* Not the last block, so nothing more to do */
/* Free the whole sub-heap if it's empty and not the original one */
if
(((
char
*
)
pFree
==
(
char
*
)
subheap
+
subheap
->
headerSize
)
&&
(
subheap
!=
&
subheap
->
heap
->
subheap
))
{
SUBHEAP
*
pPrev
=
&
subheap
->
heap
->
subheap
;
/* Remove the free block from the list */
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
/* Remove the subheap from the list */
while
(
pPrev
&&
(
pPrev
->
next
!=
subheap
))
pPrev
=
pPrev
->
next
;
if
(
pPrev
)
pPrev
->
next
=
subheap
->
next
;
/* Free the memory */
subheap
->
magic
=
0
;
VirtualFree
(
subheap
,
0
,
MEM_RELEASE
);
return
;
}
/* Decommit the end of the heap */
if
(
!
(
subheap
->
heap
->
flags
&
HEAP_SHARED
))
HEAP_Decommit
(
subheap
,
pFree
+
1
);
}
/***********************************************************************
* HEAP_ShrinkBlock
*
* Shrink an in-use block.
*/
static
void
HEAP_ShrinkBlock
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
,
DWORD
size
)
{
if
((
pArena
->
size
&
ARENA_SIZE_MASK
)
>=
size
+
HEAP_MIN_BLOCK_SIZE
)
{
HEAP_CreateFreeBlock
(
subheap
,
(
char
*
)(
pArena
+
1
)
+
size
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
size
);
/* assign size plus previous arena flags */
pArena
->
size
=
size
|
(
pArena
->
size
&
~
ARENA_SIZE_MASK
);
}
else
{
/* Turn off PREV_FREE flag in next block */
char
*
pNext
=
(
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
if
(
pNext
<
(
char
*
)
subheap
+
subheap
->
size
)
*
(
DWORD
*
)
pNext
&=
~
ARENA_FLAG_PREV_FREE
;
}
}
/***********************************************************************
* HEAP_InitSubHeap
*/
static
BOOL
HEAP_InitSubHeap
(
HEAP
*
heap
,
LPVOID
address
,
DWORD
flags
,
DWORD
commitSize
,
DWORD
totalSize
)
{
SUBHEAP
*
subheap
=
(
SUBHEAP
*
)
address
;
FREE_LIST_ENTRY
*
pEntry
;
int
i
;
/* Commit memory */
if
(
flags
&
HEAP_SHARED
)
commitSize
=
totalSize
;
/* always commit everything in a shared heap */
if
(
!
VirtualAlloc
(
address
,
commitSize
,
MEM_COMMIT
,
PAGE_EXECUTE_READWRITE
))
{
WARN
(
"Could not commit %08lx bytes for sub-heap %08lx
\n
"
,
commitSize
,
(
DWORD
)
address
);
return
FALSE
;
}
/* Fill the sub-heap structure */
subheap
->
heap
=
heap
;
subheap
->
size
=
totalSize
;
subheap
->
commitSize
=
commitSize
;
subheap
->
magic
=
SUBHEAP_MAGIC
;
if
(
subheap
!=
(
SUBHEAP
*
)
heap
)
{
/* If this is a secondary subheap, insert it into list */
subheap
->
headerSize
=
sizeof
(
SUBHEAP
);
subheap
->
next
=
heap
->
subheap
.
next
;
heap
->
subheap
.
next
=
subheap
;
}
else
{
/* If this is a primary subheap, initialize main heap */
subheap
->
headerSize
=
sizeof
(
HEAP
);
subheap
->
next
=
NULL
;
heap
->
next
=
NULL
;
heap
->
flags
=
flags
;
heap
->
magic
=
HEAP_MAGIC
;
/* Build the free lists */
for
(
i
=
0
,
pEntry
=
heap
->
freeList
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
,
pEntry
++
)
{
pEntry
->
size
=
HEAP_freeListSizes
[
i
];
pEntry
->
arena
.
size
=
0
|
ARENA_FLAG_FREE
;
pEntry
->
arena
.
next
=
i
<
HEAP_NB_FREE_LISTS
-
1
?
&
heap
->
freeList
[
i
+
1
].
arena
:
&
heap
->
freeList
[
0
].
arena
;
pEntry
->
arena
.
prev
=
i
?
&
heap
->
freeList
[
i
-
1
].
arena
:
&
heap
->
freeList
[
HEAP_NB_FREE_LISTS
-
1
].
arena
;
pEntry
->
arena
.
magic
=
ARENA_FREE_MAGIC
;
}
/* Initialize critical section */
RtlInitializeCriticalSection
(
&
heap
->
critSection
);
}
/* Create the first free block */
HEAP_CreateFreeBlock
(
subheap
,
(
LPBYTE
)
subheap
+
subheap
->
headerSize
,
subheap
->
size
-
subheap
->
headerSize
);
return
TRUE
;
}
/***********************************************************************
* HEAP_CreateSubHeap
*
* Create a sub-heap of the given size.
* If heap == NULL, creates a main heap.
*/
static
SUBHEAP
*
HEAP_CreateSubHeap
(
HEAP
*
heap
,
void
*
base
,
DWORD
flags
,
DWORD
commitSize
,
DWORD
totalSize
)
{
LPVOID
address
=
base
;
if
(
!
address
)
{
/* round-up sizes on a 64K boundary */
totalSize
=
(
totalSize
+
0xffff
)
&
0xffff0000
;
commitSize
=
(
commitSize
+
0xffff
)
&
0xffff0000
;
if
(
!
commitSize
)
commitSize
=
0x10000
;
if
(
totalSize
<
commitSize
)
totalSize
=
commitSize
;
/* allocate the memory block */
if
(
!
(
address
=
VirtualAlloc
(
NULL
,
totalSize
,
MEM_RESERVE
,
PAGE_EXECUTE_READWRITE
)))
{
WARN
(
"Could not VirtualAlloc %08lx bytes
\n
"
,
totalSize
);
return
NULL
;
}
}
/* Initialize subheap */
if
(
!
HEAP_InitSubHeap
(
heap
?
heap
:
(
HEAP
*
)
address
,
address
,
flags
,
commitSize
,
totalSize
))
{
if
(
!
base
)
VirtualFree
(
address
,
0
,
MEM_RELEASE
);
return
NULL
;
}
return
(
SUBHEAP
*
)
address
;
}
/***********************************************************************
* HEAP_FindFreeBlock
*
* Find a free block at least as large as the requested size, and make sure
* the requested size is committed.
*/
static
ARENA_FREE
*
HEAP_FindFreeBlock
(
HEAP
*
heap
,
DWORD
size
,
SUBHEAP
**
ppSubHeap
)
{
SUBHEAP
*
subheap
;
ARENA_FREE
*
pArena
;
FREE_LIST_ENTRY
*
pEntry
=
heap
->
freeList
;
/* Find a suitable free list, and in it find a block large enough */
while
(
pEntry
->
size
<
size
)
pEntry
++
;
pArena
=
pEntry
->
arena
.
next
;
while
(
pArena
!=
&
heap
->
freeList
[
0
].
arena
)
{
DWORD
arena_size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
if
(
arena_size
>=
size
)
{
subheap
=
HEAP_FindSubHeap
(
heap
,
pArena
);
if
(
!
HEAP_Commit
(
subheap
,
(
char
*
)
pArena
+
sizeof
(
ARENA_INUSE
)
+
size
+
HEAP_MIN_BLOCK_SIZE
))
return
NULL
;
*
ppSubHeap
=
subheap
;
return
pArena
;
}
pArena
=
pArena
->
next
;
}
/* If no block was found, attempt to grow the heap */
if
(
!
(
heap
->
flags
&
HEAP_GROWABLE
))
{
WARN
(
"Not enough space in heap %08lx for %08lx bytes
\n
"
,
(
DWORD
)
heap
,
size
);
return
NULL
;
}
/* make sure that we have a big enough size *committed* to fit another
* last free arena in !
* So just one heap struct, one first free arena which will eventually
* get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
* might get assigned all remaining free space in HEAP_ShrinkBlock() */
size
+=
sizeof
(
SUBHEAP
)
+
sizeof
(
ARENA_INUSE
)
+
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
subheap
=
HEAP_CreateSubHeap
(
heap
,
NULL
,
heap
->
flags
,
size
,
max
(
HEAP_DEF_SIZE
,
size
)
)))
return
NULL
;
TRACE
(
"created new sub-heap %08lx of %08lx bytes for heap %08lx
\n
"
,
(
DWORD
)
subheap
,
size
,
(
DWORD
)
heap
);
*
ppSubHeap
=
subheap
;
return
(
ARENA_FREE
*
)(
subheap
+
1
);
}
/***********************************************************************
* HEAP_IsValidArenaPtr
*
* Check that the pointer is inside the range possible for arenas.
*/
static
BOOL
HEAP_IsValidArenaPtr
(
HEAP
*
heap
,
void
*
ptr
)
{
int
i
;
SUBHEAP
*
subheap
=
HEAP_FindSubHeap
(
heap
,
ptr
);
if
(
!
subheap
)
return
FALSE
;
if
((
char
*
)
ptr
>=
(
char
*
)
subheap
+
subheap
->
headerSize
)
return
TRUE
;
if
(
subheap
!=
&
heap
->
subheap
)
return
FALSE
;
for
(
i
=
0
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
)
if
(
ptr
==
(
void
*
)
&
heap
->
freeList
[
i
].
arena
)
return
TRUE
;
return
FALSE
;
}
/***********************************************************************
* HEAP_ValidateFreeArena
*/
static
BOOL
HEAP_ValidateFreeArena
(
SUBHEAP
*
subheap
,
ARENA_FREE
*
pArena
)
{
char
*
heapEnd
=
(
char
*
)
subheap
+
subheap
->
size
;
#if !defined(ALLOW_UNALIGNED_ACCESS)
/* Check for unaligned pointers */
if
(
(
long
)
pArena
%
sizeof
(
void
*
)
!=
0
)
{
ERR
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
#endif
/* Check magic number */
if
(
pArena
->
magic
!=
ARENA_FREE_MAGIC
)
{
ERR
(
"Heap %08lx: invalid free arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check size flags */
if
(
!
(
pArena
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: bad flags %lx for free arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
pArena
->
size
&
~
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
}
/* Check arena size */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
>
heapEnd
)
{
ERR
(
"Heap %08lx: bad size %08lx for free arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
size
&
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next pointer is valid */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pArena
->
next
))
{
ERR
(
"Heap %08lx: bad next ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
next
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next arena is free */
if
(
!
(
pArena
->
next
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
next
->
magic
!=
ARENA_FREE_MAGIC
))
{
ERR
(
"Heap %08lx: next arena %08lx invalid for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
next
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev pointer is valid */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pArena
->
prev
))
{
ERR
(
"Heap %08lx: bad prev ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is free */
if
(
!
(
pArena
->
prev
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
prev
->
magic
!=
ARENA_FREE_MAGIC
))
{
/* this often means that the prev arena got overwritten
* by a memory write before that prev arena */
ERR
(
"Heap %08lx: prev arena %08lx invalid for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next block has PREV_FREE flag */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
<
heapEnd
)
{
if
(
!
(
*
(
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: free arena %08lx next block has no PREV_FREE flag
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check next block back pointer */
if
(
*
((
ARENA_FREE
**
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
-
1
)
!=
pArena
)
{
ERR
(
"Heap %08lx: arena %08lx has wrong back ptr %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
,
*
((
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
-
1
));
return
FALSE
;
}
}
return
TRUE
;
}
/***********************************************************************
* HEAP_ValidateInUseArena
*/
static
BOOL
HEAP_ValidateInUseArena
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
,
BOOL
quiet
)
{
char
*
heapEnd
=
(
char
*
)
subheap
+
subheap
->
size
;
#if !defined(ALLOW_UNALIGNED_ACCESS)
/* Check for unaligned pointers */
if
(
(
long
)
pArena
%
sizeof
(
void
*
)
!=
0
)
{
if
(
quiet
==
NOISY
)
{
ERR
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
)
)
HEAP_Dump
(
subheap
->
heap
);
}
else
if
(
WARN_ON
(
heap
)
)
{
WARN
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
)
)
HEAP_Dump
(
subheap
->
heap
);
}
return
FALSE
;
}
#endif
/* Check magic number */
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
)
{
if
(
quiet
==
NOISY
)
{
ERR
(
"Heap %08lx: invalid in-use arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
))
HEAP_Dump
(
subheap
->
heap
);
}
else
if
(
WARN_ON
(
heap
))
{
WARN
(
"Heap %08lx: invalid in-use arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
))
HEAP_Dump
(
subheap
->
heap
);
}
return
FALSE
;
}
/* Check size flags */
if
(
pArena
->
size
&
ARENA_FLAG_FREE
)
{
ERR
(
"Heap %08lx: bad flags %lx for in-use arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
pArena
->
size
&
~
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
}
/* Check arena size */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
>
heapEnd
)
{
ERR
(
"Heap %08lx: bad size %08lx for in-use arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
size
&
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check next arena PREV_FREE flag */
if
(((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
<
heapEnd
)
&&
(
*
(
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: in-use arena %08lx next block has PREV_FREE flag
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check prev free arena */
if
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
)
{
ARENA_FREE
*
pPrev
=
*
((
ARENA_FREE
**
)
pArena
-
1
);
/* Check prev pointer */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pPrev
))
{
ERR
(
"Heap %08lx: bad back ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is free */
if
(
!
(
pPrev
->
size
&
ARENA_FLAG_FREE
)
||
(
pPrev
->
magic
!=
ARENA_FREE_MAGIC
))
{
ERR
(
"Heap %08lx: prev arena %08lx invalid for in-use %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is really the previous block */
if
((
char
*
)(
pPrev
+
1
)
+
(
pPrev
->
size
&
ARENA_SIZE_MASK
)
!=
(
char
*
)
pArena
)
{
ERR
(
"Heap %08lx: prev arena %08lx is not prev for in-use %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
}
return
TRUE
;
}
/***********************************************************************
* HEAP_IsRealArena [Internal]
* Validates a block is a valid arena.
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
static
BOOL
HEAP_IsRealArena
(
HEAP
*
heapPtr
,
/* [in] ptr to the heap */
DWORD
flags
,
/* [in] Bit flags that control access during operation */
LPCVOID
block
,
/* [in] Optional pointer to memory block to validate */
BOOL
quiet
)
/* [in] Flag - if true, HEAP_ValidateInUseArena
* does not complain */
{
SUBHEAP
*
subheap
;
BOOL
ret
=
TRUE
;
if
(
!
heapPtr
||
(
heapPtr
->
magic
!=
HEAP_MAGIC
))
{
ERR
(
"Invalid heap %p!
\n
"
,
heapPtr
);
return
FALSE
;
}
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
/* calling HeapLock may result in infinite recursion, so do the critsect directly */
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
block
)
{
/* Only check this single memory block */
if
(
!
(
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
block
))
||
((
char
*
)
block
<
(
char
*
)
subheap
+
subheap
->
headerSize
+
sizeof
(
ARENA_INUSE
)))
{
if
(
quiet
==
NOISY
)
ERR
(
"Heap %p: block %p is not inside heap
\n
"
,
heapPtr
,
block
);
else
if
(
WARN_ON
(
heap
))
WARN
(
"Heap %p: block %p is not inside heap
\n
"
,
heapPtr
,
block
);
ret
=
FALSE
;
}
else
ret
=
HEAP_ValidateInUseArena
(
subheap
,
(
ARENA_INUSE
*
)
block
-
1
,
quiet
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
subheap
=
&
heapPtr
->
subheap
;
while
(
subheap
&&
ret
)
{
char
*
ptr
=
(
char
*
)
subheap
+
subheap
->
headerSize
;
while
(
ptr
<
(
char
*
)
subheap
+
subheap
->
size
)
{
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
if
(
!
HEAP_ValidateFreeArena
(
subheap
,
(
ARENA_FREE
*
)
ptr
))
{
ret
=
FALSE
;
break
;
}
ptr
+=
sizeof
(
ARENA_FREE
)
+
(
*
(
DWORD
*
)
ptr
&
ARENA_SIZE_MASK
);
}
else
{
if
(
!
HEAP_ValidateInUseArena
(
subheap
,
(
ARENA_INUSE
*
)
ptr
,
NOISY
))
{
ret
=
FALSE
;
break
;
}
ptr
+=
sizeof
(
ARENA_INUSE
)
+
(
*
(
DWORD
*
)
ptr
&
ARENA_SIZE_MASK
);
}
}
subheap
=
subheap
->
next
;
}
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
/***********************************************************************
* RtlCreateHeap (NTDLL.@)
*/
HANDLE
WINAPI
RtlCreateHeap
(
ULONG
flags
,
PVOID
addr
,
ULONG
totalSize
,
ULONG
commitSize
,
PVOID
unknown
,
PRTL_HEAP_DEFINITION
definition
)
{
SUBHEAP
*
subheap
;
/* Allocate the heap block */
if
(
!
totalSize
)
{
totalSize
=
HEAP_DEF_SIZE
;
flags
|=
HEAP_GROWABLE
;
}
/* round up sizes */
totalSize
=
(
totalSize
+
0xffff
)
&
0xffff0000
;
commitSize
=
(
commitSize
+
0xffff
)
&
0xffff0000
;
if
(
!
commitSize
)
commitSize
=
0x10000
;
if
(
totalSize
<
commitSize
)
totalSize
=
commitSize
;
if
(
!
(
subheap
=
HEAP_CreateSubHeap
(
NULL
,
addr
,
flags
,
commitSize
,
totalSize
)))
return
0
;
/* link it into the per-process heap list */
if
(
processHeap
)
{
HEAP
*
heapPtr
=
subheap
->
heap
;
RtlLockHeap
(
processHeap
);
heapPtr
->
next
=
firstHeap
;
firstHeap
=
heapPtr
;
RtlUnlockHeap
(
processHeap
);
}
else
/* assume the first heap we create is the process main heap */
{
set_process_heap
(
(
HANDLE
)
subheap
->
heap
);
}
return
(
HANDLE
)
subheap
;
}
/***********************************************************************
* RtlDestroyHeap (NTDLL.@)
*/
HANDLE
WINAPI
RtlDestroyHeap
(
HANDLE
heap
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
SUBHEAP
*
subheap
;
TRACE
(
"%08x
\n
"
,
heap
);
if
(
!
heapPtr
)
return
heap
;
if
(
heap
==
processHeap
)
return
heap
;
/* cannot delete the main process heap */
else
/* remove it from the per-process list */
{
HEAP
**
pptr
;
RtlLockHeap
(
processHeap
);
pptr
=
&
firstHeap
;
while
(
*
pptr
&&
*
pptr
!=
heapPtr
)
pptr
=
&
(
*
pptr
)
->
next
;
if
(
*
pptr
)
*
pptr
=
(
*
pptr
)
->
next
;
RtlUnlockHeap
(
processHeap
);
}
RtlDeleteCriticalSection
(
&
heapPtr
->
critSection
);
subheap
=
&
heapPtr
->
subheap
;
while
(
subheap
)
{
SUBHEAP
*
next
=
subheap
->
next
;
VirtualFree
(
subheap
,
0
,
MEM_RELEASE
);
subheap
=
next
;
}
return
0
;
}
/***********************************************************************
* RtlAllocateHeap (NTDLL.@)
*
* NOTE: does not set last error.
*/
PVOID
WINAPI
RtlAllocateHeap
(
HANDLE
heap
,
ULONG
flags
,
ULONG
size
)
{
ARENA_FREE
*
pArena
;
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
subheap
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
/* Validate the parameters */
if
(
!
heapPtr
)
return
NULL
;
flags
&=
HEAP_GENERATE_EXCEPTIONS
|
HEAP_NO_SERIALIZE
|
HEAP_ZERO_MEMORY
;
flags
|=
heapPtr
->
flags
;
size
=
(
size
+
3
)
&
~
3
;
if
(
size
<
HEAP_MIN_BLOCK_SIZE
)
size
=
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
/* Locate a suitable free block */
if
(
!
(
pArena
=
HEAP_FindFreeBlock
(
heapPtr
,
size
,
&
subheap
)))
{
TRACE
(
"(%08x,%08lx,%08lx): returning NULL
\n
"
,
heap
,
flags
,
size
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
if
(
flags
&
HEAP_GENERATE_EXCEPTIONS
)
RtlRaiseStatus
(
STATUS_NO_MEMORY
);
return
NULL
;
}
/* Remove the arena from the free list */
pArena
->
next
->
prev
=
pArena
->
prev
;
pArena
->
prev
->
next
=
pArena
->
next
;
/* Build the in-use arena */
pInUse
=
(
ARENA_INUSE
*
)
pArena
;
/* in-use arena is smaller than free arena,
* so we have to add the difference to the size */
pInUse
->
size
=
(
pInUse
->
size
&
~
ARENA_FLAG_FREE
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
pInUse
->
magic
=
ARENA_INUSE_MAGIC
;
/* Shrink the block */
HEAP_ShrinkBlock
(
subheap
,
pInUse
,
size
);
if
(
flags
&
HEAP_ZERO_MEMORY
)
memset
(
pInUse
+
1
,
0
,
pInUse
->
size
&
ARENA_SIZE_MASK
);
else
if
(
TRACE_ON
(
heap
))
memset
(
pInUse
+
1
,
ARENA_INUSE_FILLER
,
pInUse
->
size
&
ARENA_SIZE_MASK
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
size
,
(
DWORD
)(
pInUse
+
1
)
);
return
(
LPVOID
)(
pInUse
+
1
);
}
/***********************************************************************
* RtlFreeHeap (NTDLL.@)
*/
BOOLEAN
WINAPI
RtlFreeHeap
(
HANDLE
heap
,
ULONG
flags
,
PVOID
ptr
)
{
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
subheap
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
/* Validate the parameters */
if
(
!
ptr
)
return
TRUE
;
/* freeing a NULL ptr isn't an error in Win2k */
if
(
!
heapPtr
)
{
set_status
(
STATUS_INVALID_HANDLE
);
return
FALSE
;
}
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
set_status
(
STATUS_INVALID_PARAMETER
);
TRACE
(
"(%08x,%08lx,%08lx): returning FALSE
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
);
return
FALSE
;
}
/* Turn the block into a free block */
pInUse
=
(
ARENA_INUSE
*
)
ptr
-
1
;
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
pInUse
);
HEAP_MakeInUseBlockFree
(
subheap
,
pInUse
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning TRUE
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
);
return
TRUE
;
}
/***********************************************************************
* RtlReAllocateHeap (NTDLL.@)
*/
PVOID
WINAPI
RtlReAllocateHeap
(
HANDLE
heap
,
ULONG
flags
,
PVOID
ptr
,
ULONG
size
)
{
ARENA_INUSE
*
pArena
;
DWORD
oldSize
;
HEAP
*
heapPtr
;
SUBHEAP
*
subheap
;
if
(
!
ptr
)
return
RtlAllocateHeap
(
heap
,
flags
,
size
);
/* FIXME: correct? */
if
(
!
(
heapPtr
=
HEAP_GetPtr
(
heap
)))
{
set_status
(
STATUS_INVALID_HANDLE
);
return
FALSE
;
}
/* Validate the parameters */
flags
&=
HEAP_GENERATE_EXCEPTIONS
|
HEAP_NO_SERIALIZE
|
HEAP_ZERO_MEMORY
|
HEAP_REALLOC_IN_PLACE_ONLY
;
flags
|=
heapPtr
->
flags
;
size
=
(
size
+
3
)
&
~
3
;
if
(
size
<
HEAP_MIN_BLOCK_SIZE
)
size
=
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
set_status
(
STATUS_INVALID_PARAMETER
);
TRACE
(
"(%08x,%08lx,%08lx,%08lx): returning NULL
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
size
);
return
NULL
;
}
/* Check if we need to grow the block */
pArena
=
(
ARENA_INUSE
*
)
ptr
-
1
;
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
pArena
);
oldSize
=
(
pArena
->
size
&
ARENA_SIZE_MASK
);
if
(
size
>
oldSize
)
{
char
*
pNext
=
(
char
*
)(
pArena
+
1
)
+
oldSize
;
if
((
pNext
<
(
char
*
)
subheap
+
subheap
->
size
)
&&
(
*
(
DWORD
*
)
pNext
&
ARENA_FLAG_FREE
)
&&
(
oldSize
+
(
*
(
DWORD
*
)
pNext
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
)
>=
size
))
{
/* The next block is free and large enough */
ARENA_FREE
*
pFree
=
(
ARENA_FREE
*
)
pNext
;
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
pArena
->
size
+=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pFree
);
if
(
!
HEAP_Commit
(
subheap
,
(
char
*
)
pArena
+
sizeof
(
ARENA_INUSE
)
+
size
+
HEAP_MIN_BLOCK_SIZE
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
if
(
flags
&
HEAP_GENERATE_EXCEPTIONS
)
RtlRaiseStatus
(
STATUS_NO_MEMORY
);
set_status
(
STATUS_NO_MEMORY
);
return
NULL
;
}
HEAP_ShrinkBlock
(
subheap
,
pArena
,
size
);
}
else
/* Do it the hard way */
{
ARENA_FREE
*
pNew
;
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
newsubheap
;
if
((
flags
&
HEAP_REALLOC_IN_PLACE_ONLY
)
||
!
(
pNew
=
HEAP_FindFreeBlock
(
heapPtr
,
size
,
&
newsubheap
)))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
if
(
flags
&
HEAP_GENERATE_EXCEPTIONS
)
RtlRaiseStatus
(
STATUS_NO_MEMORY
);
set_status
(
STATUS_NO_MEMORY
);
return
NULL
;
}
/* Build the in-use arena */
pNew
->
next
->
prev
=
pNew
->
prev
;
pNew
->
prev
->
next
=
pNew
->
next
;
pInUse
=
(
ARENA_INUSE
*
)
pNew
;
pInUse
->
size
=
(
pInUse
->
size
&
~
ARENA_FLAG_FREE
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
pInUse
->
magic
=
ARENA_INUSE_MAGIC
;
HEAP_ShrinkBlock
(
newsubheap
,
pInUse
,
size
);
memcpy
(
pInUse
+
1
,
pArena
+
1
,
oldSize
);
/* Free the previous block */
HEAP_MakeInUseBlockFree
(
subheap
,
pArena
);
subheap
=
newsubheap
;
pArena
=
pInUse
;
}
}
else
HEAP_ShrinkBlock
(
subheap
,
pArena
,
size
);
/* Shrink the block */
/* Clear the extra bytes if needed */
if
(
size
>
oldSize
)
{
if
(
flags
&
HEAP_ZERO_MEMORY
)
memset
(
(
char
*
)(
pArena
+
1
)
+
oldSize
,
0
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
oldSize
);
else
if
(
TRACE_ON
(
heap
))
memset
(
(
char
*
)(
pArena
+
1
)
+
oldSize
,
ARENA_INUSE_FILLER
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
oldSize
);
}
/* Return the new arena */
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
size
,
(
DWORD
)(
pArena
+
1
)
);
return
(
LPVOID
)(
pArena
+
1
);
}
/***********************************************************************
* RtlCompactHeap (NTDLL.@)
*/
ULONG
WINAPI
RtlCompactHeap
(
HANDLE
heap
,
ULONG
flags
)
{
FIXME
(
"stub
\n
"
);
return
0
;
}
/***********************************************************************
* RtlLockHeap (NTDLL.@)
*/
BOOLEAN
WINAPI
RtlLockHeap
(
HANDLE
heap
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
return
FALSE
;
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
return
TRUE
;
}
/***********************************************************************
* RtlUnlockHeap (NTDLL.@)
*/
BOOLEAN
WINAPI
RtlUnlockHeap
(
HANDLE
heap
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
return
FALSE
;
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
TRUE
;
}
/***********************************************************************
* RtlSizeHeap (NTDLL.@)
*/
ULONG
WINAPI
RtlSizeHeap
(
HANDLE
heap
,
ULONG
flags
,
PVOID
ptr
)
{
DWORD
ret
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
{
set_status
(
STATUS_INVALID_HANDLE
);
return
(
ULONG
)
-
1
;
}
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlEnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
set_status
(
STATUS_INVALID_PARAMETER
);
ret
=
(
ULONG
)
-
1
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
-
1
;
ret
=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
RtlLeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
ret
);
return
ret
;
}
/***********************************************************************
* RtlValidateHeap (NTDLL.@)
*/
BOOLEAN
WINAPI
RtlValidateHeap
(
HANDLE
heap
,
ULONG
flags
,
PCVOID
block
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
return
FALSE
;
return
HEAP_IsRealArena
(
heapPtr
,
flags
,
block
,
QUIET
);
}
/***********************************************************************
* RtlWalkHeap (NTDLL.@)
*
* FIXME: the PROCESS_HEAP_ENTRY flag values seem different between this
* function and HeapWalk. To be checked.
*/
NTSTATUS
WINAPI
RtlWalkHeap
(
HANDLE
heap
,
PVOID
entry_ptr
)
{
LPPROCESS_HEAP_ENTRY
entry
=
entry_ptr
;
/* FIXME */
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
SUBHEAP
*
sub
,
*
currentheap
=
NULL
;
NTSTATUS
ret
;
char
*
ptr
;
int
region_index
=
0
;
FIXME
(
"not fully compatible
\n
"
);
if
(
!
heapPtr
||
!
entry
)
return
STATUS_INVALID_PARAMETER
;
if
(
!
(
heapPtr
->
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
/* set ptr to the next arena to be examined */
if
(
!
entry
->
lpData
)
/* first call (init) ? */
{
TRACE
(
"begin walking of heap 0x%08x.
\n
"
,
heap
);
currentheap
=
&
heapPtr
->
subheap
;
ptr
=
(
char
*
)
currentheap
+
currentheap
->
headerSize
;
}
else
{
ptr
=
entry
->
lpData
;
sub
=
&
heapPtr
->
subheap
;
while
(
sub
)
{
if
(((
char
*
)
ptr
>=
(
char
*
)
sub
)
&&
((
char
*
)
ptr
<
(
char
*
)
sub
+
sub
->
size
))
{
currentheap
=
sub
;
break
;
}
sub
=
sub
->
next
;
region_index
++
;
}
if
(
currentheap
==
NULL
)
{
ERR
(
"no matching subheap found, shouldn't happen !
\n
"
);
ret
=
STATUS_NO_MORE_ENTRIES
;
goto
HW_end
;
}
ptr
+=
entry
->
cbData
;
/* point to next arena */
if
(
ptr
>
(
char
*
)
currentheap
+
currentheap
->
size
-
1
)
{
/* proceed with next subheap */
if
(
!
(
currentheap
=
currentheap
->
next
))
{
/* successfully finished */
TRACE
(
"end reached.
\n
"
);
ret
=
STATUS_NO_MORE_ENTRIES
;
goto
HW_end
;
}
ptr
=
(
char
*
)
currentheap
+
currentheap
->
headerSize
;
}
}
entry
->
wFlags
=
0
;
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
ARENA_FREE
*
pArena
=
(
ARENA_FREE
*
)
ptr
;
/*TRACE("free, magic: %04x\n", pArena->magic);*/
entry
->
lpData
=
pArena
+
1
;
entry
->
cbData
=
pArena
->
size
&
ARENA_SIZE_MASK
;
entry
->
cbOverhead
=
sizeof
(
ARENA_FREE
);
entry
->
wFlags
=
PROCESS_HEAP_UNCOMMITTED_RANGE
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
/*TRACE("busy, magic: %04x\n", pArena->magic);*/
entry
->
lpData
=
pArena
+
1
;
entry
->
cbData
=
pArena
->
size
&
ARENA_SIZE_MASK
;
entry
->
cbOverhead
=
sizeof
(
ARENA_INUSE
);
entry
->
wFlags
=
PROCESS_HEAP_ENTRY_BUSY
;
/* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
and PROCESS_HEAP_ENTRY_DDESHARE yet */
}
entry
->
iRegionIndex
=
region_index
;
/* first element of heap ? */
if
(
ptr
==
(
char
*
)(
currentheap
+
currentheap
->
headerSize
))
{
entry
->
wFlags
|=
PROCESS_HEAP_REGION
;
entry
->
u
.
Region
.
dwCommittedSize
=
currentheap
->
commitSize
;
entry
->
u
.
Region
.
dwUnCommittedSize
=
currentheap
->
size
-
currentheap
->
commitSize
;
entry
->
u
.
Region
.
lpFirstBlock
=
/* first valid block */
currentheap
+
currentheap
->
headerSize
;
entry
->
u
.
Region
.
lpLastBlock
=
/* first invalid block */
currentheap
+
currentheap
->
size
;
}
ret
=
STATUS_SUCCESS
;
HW_end
:
if
(
!
(
heapPtr
->
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
/***********************************************************************
* RtlGetProcessHeaps (NTDLL.@)
*/
ULONG
WINAPI
RtlGetProcessHeaps
(
ULONG
count
,
HANDLE
*
heaps
)
{
DWORD
total
;
HEAP
*
ptr
;
if
(
!
processHeap
)
return
0
;
/* should never happen */
total
=
1
;
/* main heap */
RtlLockHeap
(
processHeap
);
for
(
ptr
=
firstHeap
;
ptr
;
ptr
=
ptr
->
next
)
total
++
;
if
(
total
<=
count
)
{
*
heaps
++
=
(
HANDLE
)
processHeap
;
for
(
ptr
=
firstHeap
;
ptr
;
ptr
=
ptr
->
next
)
*
heaps
++
=
(
HANDLE
)
ptr
;
}
RtlUnlockHeap
(
processHeap
);
return
total
;
}
dlls/ntdll/ntdll.spec
View file @
b0f58617
...
...
@@ -300,7 +300,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stub RtlCheckRegistryKey
@ stub RtlClearAllBits
@ stdcall RtlClearBits(long long long) RtlClearBits
@ st
ub
RtlCompactHeap
@ st
dcall RtlCompactHeap(long long)
RtlCompactHeap
@ stdcall RtlCompareMemory(ptr ptr long) RtlCompareMemory
@ stub RtlCompareMemoryUlong
@ stdcall RtlCompareString(ptr ptr long) RtlCompareString
...
...
@@ -406,7 +406,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stub RtlGetNtGlobalFlags
@ stdcall RtlGetNtProductType(ptr) RtlGetNtProductType
@ stdcall RtlGetOwnerSecurityDescriptor(ptr ptr ptr) RtlGetOwnerSecurityDescriptor
@ st
ub
RtlGetProcessHeaps
@ st
dcall RtlGetProcessHeaps(long ptr)
RtlGetProcessHeaps
@ stdcall RtlGetSaclSecurityDescriptor(ptr ptr ptr ptr)RtlGetSaclSecurityDescriptor
@ stub RtlGetUserInfoHeap
@ stdcall RtlIdentifierAuthoritySid(ptr) RtlIdentifierAuthoritySid
...
...
@@ -446,7 +446,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stdcall RtlLengthSecurityDescriptor(ptr) RtlLengthSecurityDescriptor
@ stdcall RtlLengthSid(ptr) RtlLengthSid
@ stub RtlLocalTimeToSystemTime
@ st
ub
RtlLockHeap
@ st
dcall RtlLockHeap(long)
RtlLockHeap
@ stub RtlLookupElementGenericTable
@ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr) RtlMakeSelfRelativeSD
@ stub RtlMapGenericMask
...
...
@@ -482,7 +482,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stdcall RtlRaiseException(ptr) RtlRaiseException
@ stdcall RtlRaiseStatus(long) RtlRaiseStatus
@ stub RtlRandom
@ st
ub
RtlReAllocateHeap
@ st
dcall RtlReAllocateHeap(long long ptr long)
RtlReAllocateHeap
@ stub RtlRealPredecessor
@ stub RtlRealSuccessor
@ stdcall RtlReleasePebLock() RtlReleasePebLock
...
...
@@ -508,7 +508,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stub RtlSetTimeZoneInformation
@ stub RtlSetUserFlagsHeap
@ stub RtlSetUserValueHeap
@ stdcall RtlSizeHeap(long long
long) HeapSize
@ stdcall RtlSizeHeap(long long
ptr) RtlSizeHeap
@ stub RtlSplay
@ stub RtlStartRXact
@ stdcall RtlSubAuthorityCountSid(ptr) RtlSubAuthorityCountSid
...
...
@@ -532,7 +532,7 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stdcall RtlUnicodeToMultiByteSize(ptr wstr long) RtlUnicodeToMultiByteSize
@ stdcall RtlUnicodeToOemN(ptr long ptr ptr long) RtlUnicodeToOemN
@ stub RtlUniform
@ st
ub
RtlUnlockHeap
@ st
dcall RtlUnlockHeap(long)
RtlUnlockHeap
@ stdcall RtlUnwind(ptr ptr ptr long) RtlUnwind
@ stub RtlUpcaseUnicodeChar
@ stdcall RtlUpcaseUnicodeString(ptr ptr long) RtlUpcaseUnicodeString
...
...
@@ -548,9 +548,9 @@ debug_channels (atom cdrom console debug delayhlp dll dosfs dosmem file fixup
@ stub RtlValidAcl
@ stdcall RtlValidSecurityDescriptor(ptr) RtlValidSecurityDescriptor
@ stdcall RtlValidSid(ptr) RtlValidSid
@ st
ub
RtlValidateHeap
@ st
dcall RtlValidateHeap(long long ptr)
RtlValidateHeap
@ stub RtlValidateProcessHeaps
@ st
ub
RtlWalkHeap
@ st
dcall RtlWalkHeap(long ptr)
RtlWalkHeap
@ stub RtlWriteRegistryValue
@ stub RtlZeroHeap
@ stdcall RtlZeroMemory(ptr long) RtlZeroMemory
...
...
dlls/ntdll/rtl.c
View file @
b0f58617
...
...
@@ -213,64 +213,6 @@ void WINAPI RtlDumpResource(LPRTL_RWLOCK rwl)
}
/*
* heap functions
*/
/******************************************************************************
* RtlCreateHeap [NTDLL.@]
*/
HANDLE
WINAPI
RtlCreateHeap
(
ULONG
Flags
,
PVOID
BaseAddress
,
ULONG
SizeToReserve
,
ULONG
SizeToCommit
,
PVOID
Unknown
,
PRTL_HEAP_DEFINITION
Definition
)
{
FIXME
(
"(0x%08lx, %p, 0x%08lx, 0x%08lx, %p, %p) semi-stub
\n
"
,
Flags
,
BaseAddress
,
SizeToReserve
,
SizeToCommit
,
Unknown
,
Definition
);
return
HeapCreate
(
Flags
,
SizeToCommit
,
SizeToReserve
);
}
/******************************************************************************
* RtlAllocateHeap [NTDLL.@]
*/
PVOID
WINAPI
RtlAllocateHeap
(
HANDLE
Heap
,
ULONG
Flags
,
ULONG
Size
)
{
TRACE
(
"(0x%08x, 0x%08lx, 0x%08lx) semi stub
\n
"
,
Heap
,
Flags
,
Size
);
return
HeapAlloc
(
Heap
,
Flags
,
Size
);
}
/******************************************************************************
* RtlFreeHeap [NTDLL.@]
*/
BOOLEAN
WINAPI
RtlFreeHeap
(
HANDLE
Heap
,
ULONG
Flags
,
PVOID
Address
)
{
TRACE
(
"(0x%08x, 0x%08lx, %p) semi stub
\n
"
,
Heap
,
Flags
,
Address
);
return
HeapFree
(
Heap
,
Flags
,
Address
);
}
/******************************************************************************
* RtlDestroyHeap [NTDLL.@]
*/
HANDLE
WINAPI
RtlDestroyHeap
(
HANDLE
Heap
)
{
TRACE
(
"(0x%08x) semi stub
\n
"
,
Heap
);
if
(
!
HeapDestroy
(
Heap
))
return
Heap
;
return
0
;
}
/*
* misc functions
*/
...
...
dlls/ole32/ifs.c
View file @
b0f58617
...
...
@@ -143,25 +143,32 @@ ULONG WINAPI IMalloc16_fnRelease(IMalloc16* iface) {
SEGPTR
WINAPI
IMalloc16_fnAlloc
(
IMalloc16
*
iface
,
DWORD
cb
)
{
ICOM_THIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->Alloc(%ld)
\n
"
,
This
,
cb
);
return
MapLS
(
HeapAlloc
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
cb
)
);
return
MapLS
(
HeapAlloc
(
GetProcessHeap
(),
0
,
cb
)
);
}
/******************************************************************************
* IMalloc16_Realloc [COMPOBJ.504]
*/
SEGPTR
WINAPI
IMalloc16_fnRealloc
(
IMalloc16
*
iface
,
SEGPTR
pv
,
DWORD
cb
)
{
ICOM_THIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->Realloc(%08lx,%ld)
\n
"
,
This
,
pv
,
cb
);
return
MapLS
(
HeapReAlloc
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
MapSL
(
pv
),
cb
)
);
SEGPTR
WINAPI
IMalloc16_fnRealloc
(
IMalloc16
*
iface
,
SEGPTR
pv
,
DWORD
cb
)
{
SEGPTR
ret
;
ICOM_THIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->Realloc(%08lx,%ld)
\n
"
,
This
,
pv
,
cb
);
ret
=
MapLS
(
HeapReAlloc
(
GetProcessHeap
(),
0
,
MapSL
(
pv
),
cb
)
);
UnMapLS
(
pv
);
return
ret
;
}
/******************************************************************************
* IMalloc16_Free [COMPOBJ.505]
*/
VOID
WINAPI
IMalloc16_fnFree
(
IMalloc16
*
iface
,
SEGPTR
pv
)
{
ICOM_THIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->Free(%08lx)
\n
"
,
This
,
pv
);
HeapFree
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
MapSL
(
pv
)
);
VOID
WINAPI
IMalloc16_fnFree
(
IMalloc16
*
iface
,
SEGPTR
pv
)
{
void
*
ptr
=
MapSL
(
pv
);
ICOM_THIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->Free(%08lx)
\n
"
,
This
,
pv
);
UnMapLS
(
pv
);
HeapFree
(
GetProcessHeap
(),
0
,
ptr
);
}
/******************************************************************************
...
...
@@ -171,7 +178,7 @@ DWORD WINAPI IMalloc16_fnGetSize(const IMalloc16* iface,SEGPTR pv)
{
ICOM_CTHIS
(
IMalloc16Impl
,
iface
);
TRACE
(
"(%p)->GetSize(%08lx)
\n
"
,
This
,
pv
);
return
HeapSize
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
MapSL
(
pv
)
);
return
HeapSize
(
GetProcessHeap
(),
0
,
MapSL
(
pv
)
);
}
/******************************************************************************
...
...
graphics/win16drv/font.c
View file @
b0f58617
...
...
@@ -95,7 +95,7 @@ HFONT WIN16DRV_FONT_SelectObject( DC * dc, HFONT hfont)
&
physDev
->
lf
,
0
,
0
);
if
(
physDev
->
FontInfo
&&
HeapSize
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
physDev
->
FontInfo
)
<
nSize
)
HeapSize
(
GetProcessHeap
(),
0
,
physDev
->
FontInfo
)
<
nSize
)
{
SEGPTR_FREE
(
physDev
->
FontInfo
);
physDev
->
FontInfo
=
NULL
;
...
...
include/heap.h
View file @
b0f58617
...
...
@@ -14,18 +14,16 @@
#include "wine/unicode.h"
#include "wine/windef16.h"
/* for SEGPTR */
extern
SEGPTR
HEAP_GetSegptr
(
HANDLE
heap
,
DWORD
flags
,
LPCVOID
ptr
);
/* SEGPTR helper macros */
#define SEGPTR_ALLOC(size) \
(HeapAlloc( GetProcessHeap(),
HEAP_WINE_SEGPTR
, (size) ))
(HeapAlloc( GetProcessHeap(),
0
, (size) ))
#define SEGPTR_NEW(type) \
((type *)HeapAlloc( GetProcessHeap(),
HEAP_WINE_SEGPTR
, sizeof(type) ))
((type *)HeapAlloc( GetProcessHeap(),
0
, sizeof(type) ))
#define SEGPTR_STRDUP_WtoA(str) \
(HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(),
HEAP_WINE_SEGPTR
, (str) ) : (LPSTR)(str))
(HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(),
0
, (str) ) : (LPSTR)(str))
#define SEGPTR_FREE(ptr) \
(HIWORD(ptr) ? HeapFree( GetProcessHeap(),
HEAP_WINE_SEGPTR
, (ptr) ) : 0)
(HIWORD(ptr) ? HeapFree( GetProcessHeap(),
0
, (ptr) ) : 0)
#define SEGPTR_GET(ptr) MapLS(ptr)
inline
static
LPSTR
SEGPTR_STRDUP
(
LPCSTR
str
)
...
...
@@ -33,7 +31,7 @@ inline static LPSTR SEGPTR_STRDUP( LPCSTR str )
if
(
HIWORD
(
str
))
{
INT
len
=
strlen
(
str
)
+
1
;
LPSTR
p
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_WINE_SEGPTR
,
len
);
LPSTR
p
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
if
(
p
)
memcpy
(
p
,
str
,
len
);
return
p
;
}
...
...
include/ntddk.h
View file @
b0f58617
...
...
@@ -723,6 +723,7 @@ BOOLEAN WINAPI RtlUnlockHeap(HANDLE);
ULONG
WINAPI
RtlSizeHeap
(
HANDLE
,
ULONG
,
PVOID
);
BOOLEAN
WINAPI
RtlValidateHeap
(
HANDLE
,
ULONG
,
PCVOID
);
ULONG
WINAPI
RtlGetProcessHeaps
(
ULONG
,
HANDLE
*
);
NTSTATUS
WINAPI
RtlWalkHeap
(
HANDLE
,
PVOID
);
/* exception */
...
...
include/winbase.h
View file @
b0f58617
...
...
@@ -985,20 +985,33 @@ BOOL WINAPI GetVersionExW(OSVERSIONINFOW*);
/*int WinMain(HINSTANCE, HINSTANCE prev, char *cmd, int show);*/
LONG
WINAPI
RtlEnterCriticalSection
(
CRITICAL_SECTION
*
crit
);
LONG
WINAPI
RtlLeaveCriticalSection
(
CRITICAL_SECTION
*
crit
);
LONG
WINAPI
RtlDeleteCriticalSection
(
CRITICAL_SECTION
*
crit
);
BOOL
WINAPI
RtlTryEnterCriticalSection
(
CRITICAL_SECTION
*
crit
);
/* FIXME: need to use defines because we don't have proper imports yet */
/* FIXME: need to use defines because we don't have proper imports everywhere yet */
#ifndef have_proper_imports
LONG
WINAPI
RtlEnterCriticalSection
(
CRITICAL_SECTION
*
crit
);
LONG
WINAPI
RtlLeaveCriticalSection
(
CRITICAL_SECTION
*
crit
);
LONG
WINAPI
RtlDeleteCriticalSection
(
CRITICAL_SECTION
*
crit
);
BOOL
WINAPI
RtlTryEnterCriticalSection
(
CRITICAL_SECTION
*
crit
);
PVOID
WINAPI
RtlAllocateHeap
(
HANDLE
,
ULONG
,
ULONG
);
BOOLEAN
WINAPI
RtlFreeHeap
(
HANDLE
,
ULONG
,
PVOID
);
PVOID
WINAPI
RtlReAllocateHeap
(
HANDLE
,
ULONG
,
PVOID
,
ULONG
);
ULONG
WINAPI
RtlSizeHeap
(
HANDLE
,
ULONG
,
PVOID
);
#define HeapAlloc(heap,flags,size) RtlAllocateHeap(heap,flags,size)
#define HeapFree(heap,flags,ptr) RtlFreeHeap(heap,flags,ptr)
#define HeapReAlloc(heap,flags,ptr,size) RtlReAllocateHeap(heap,flags,ptr,size)
#define HeapSize(heap,flags,ptr) RtlSizeHeap(heap,flags,ptr)
#define EnterCriticalSection(crit) RtlEnterCriticalSection(crit)
#define LeaveCriticalSection(crit) RtlLeaveCriticalSection(crit)
#define DeleteCriticalSection(crit) RtlDeleteCriticalSection(crit)
#define TryEnterCriticalSection(crit) RtlTryEnterCriticalSection(crit)
#if 0
void WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
BOOL WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
#else
LPVOID
WINAPI
HeapAlloc
(
HANDLE
,
DWORD
,
DWORD
);
BOOL
WINAPI
HeapFree
(
HANDLE
,
DWORD
,
LPVOID
);
LPVOID
WINAPI
HeapReAlloc
(
HANDLE
,
DWORD
,
LPVOID
,
DWORD
);
DWORD
WINAPI
HeapSize
(
HANDLE
,
DWORD
,
LPVOID
);
void
WINAPI
DeleteCriticalSection
(
CRITICAL_SECTION
*
lpCrit
);
void
WINAPI
EnterCriticalSection
(
CRITICAL_SECTION
*
lpCrit
);
BOOL
WINAPI
TryEnterCriticalSection
(
CRITICAL_SECTION
*
lpCrit
);
void
WINAPI
LeaveCriticalSection
(
CRITICAL_SECTION
*
lpCrit
);
#endif
void
WINAPI
InitializeCriticalSection
(
CRITICAL_SECTION
*
lpCrit
);
...
...
@@ -1237,14 +1250,10 @@ BOOL WINAPI GetUserNameA(LPSTR,LPDWORD);
BOOL
WINAPI
GetUserNameW
(
LPWSTR
,
LPDWORD
);
#define GetUserName WINELIB_NAME_AW(GetUserName)
VOID
WINAPI
GlobalMemoryStatus
(
LPMEMORYSTATUS
);
LPVOID
WINAPI
HeapAlloc
(
HANDLE
,
DWORD
,
DWORD
);
DWORD
WINAPI
HeapCompact
(
HANDLE
,
DWORD
);
HANDLE
WINAPI
HeapCreate
(
DWORD
,
DWORD
,
DWORD
);
BOOL
WINAPI
HeapDestroy
(
HANDLE
);
BOOL
WINAPI
HeapFree
(
HANDLE
,
DWORD
,
LPVOID
);
BOOL
WINAPI
HeapLock
(
HANDLE
);
LPVOID
WINAPI
HeapReAlloc
(
HANDLE
,
DWORD
,
LPVOID
,
DWORD
);
DWORD
WINAPI
HeapSize
(
HANDLE
,
DWORD
,
LPVOID
);
BOOL
WINAPI
HeapUnlock
(
HANDLE
);
BOOL
WINAPI
HeapValidate
(
HANDLE
,
DWORD
,
LPCVOID
);
BOOL
WINAPI
HeapWalk
(
HANDLE
,
LPPROCESS_HEAP_ENTRY
);
...
...
include/winnt.h
View file @
b0f58617
...
...
@@ -524,11 +524,7 @@ typedef struct _SINGLE_LIST_ENTRY {
/* This flag allows it to create heaps shared by all processes under win95,
FIXME: correct name */
#define HEAP_SHARED 0x04000000
#define HEAP_WINE_SEGPTR 0x10000000
/* Not a Win32 flag */
#define HEAP_WINE_CODESEG 0x20000000
/* Not a Win32 flag */
#define HEAP_WINE_CODE16SEG 0x40000000
/* Not a Win32 flag */
#define HEAP_SHARED 0x04000000
/* Processor feature flags. */
#define PF_FLOATING_POINT_PRECISION_ERRATA 0
...
...
memory/heap.c
View file @
b0f58617
...
...
@@ -12,1056 +12,103 @@
#include <stdio.h>
#include <string.h>
#include "wine/winbase16.h"
#include "wine/unicode.h"
#include "selectors.h"
#include "global.h"
#include "winbase.h"
#include "winerror.h"
#include "winnt.h"
#include "heap.h"
#include "toolhelp.h"
#include "debugtools.h"
#include "winnls.h"
DEFAULT_DEBUG_CHANNEL
(
heap
);
/* Note: the heap data structures are based on what Pietrek describes in his
* book 'Windows 95 System Programming Secrets'. The layout is not exactly
* the same, but could be easily adapted if it turns out some programs
* require it.
*/
typedef
struct
tagARENA_INUSE
{
DWORD
size
;
/* Block size; must be the first field */
WORD
magic
;
/* Magic number */
WORD
threadId
;
/* Allocating thread id */
void
*
callerEIP
;
/* EIP of caller upon allocation */
}
ARENA_INUSE
;
typedef
struct
tagARENA_FREE
{
DWORD
size
;
/* Block size; must be the first field */
WORD
magic
;
/* Magic number */
WORD
threadId
;
/* Freeing thread id */
struct
tagARENA_FREE
*
next
;
/* Next free arena */
struct
tagARENA_FREE
*
prev
;
/* Prev free arena */
}
ARENA_FREE
;
#define ARENA_FLAG_FREE 0x00000001
/* flags OR'ed with arena size */
#define ARENA_FLAG_PREV_FREE 0x00000002
#define ARENA_SIZE_MASK 0xfffffffc
#define ARENA_INUSE_MAGIC 0x4842
/* Value for arena 'magic' field */
#define ARENA_FREE_MAGIC 0x4846
/* Value for arena 'magic' field */
#define ARENA_INUSE_FILLER 0x55
#define ARENA_FREE_FILLER 0xaa
#define QUIET 1
/* Suppress messages */
#define NOISY 0
/* Report all errors */
#define HEAP_NB_FREE_LISTS 4
/* Number of free lists */
/* Max size of the blocks on the free lists */
static
const
DWORD
HEAP_freeListSizes
[
HEAP_NB_FREE_LISTS
]
=
{
0x20
,
0x80
,
0x200
,
0xffffffff
};
typedef
struct
{
DWORD
size
;
ARENA_FREE
arena
;
}
FREE_LIST_ENTRY
;
struct
tagHEAP
;
typedef
struct
tagSUBHEAP
{
DWORD
size
;
/* Size of the whole sub-heap */
DWORD
commitSize
;
/* Committed size of the sub-heap */
DWORD
headerSize
;
/* Size of the heap header */
struct
tagSUBHEAP
*
next
;
/* Next sub-heap */
struct
tagHEAP
*
heap
;
/* Main heap structure */
DWORD
magic
;
/* Magic number */
WORD
selector
;
/* Selector for HEAP_WINE_SEGPTR heaps */
}
SUBHEAP
;
#define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
typedef
struct
tagHEAP
{
SUBHEAP
subheap
;
/* First sub-heap */
struct
tagHEAP
*
next
;
/* Next heap for this process */
FREE_LIST_ENTRY
freeList
[
HEAP_NB_FREE_LISTS
];
/* Free lists */
CRITICAL_SECTION
critSection
;
/* Critical section for serialization */
DWORD
flags
;
/* Heap flags */
DWORD
magic
;
/* Magic number */
}
HEAP
;
#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
#define HEAP_DEF_SIZE 0x110000
/* Default heap size = 1Mb + 64Kb */
#define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE))
/* Min. heap block size */
#define COMMIT_MASK 0xffff
/* bitmask for commit/decommit granularity */
static
HEAP
*
systemHeap
;
/* globally shared heap */
static
HEAP
*
processHeap
;
/* main process heap */
static
HEAP
*
segptrHeap
;
/* main segptr heap */
static
HEAP
*
firstHeap
;
/* head of secondary heaps list */
/* address where we try to map the system heap */
#define SYSTEM_HEAP_BASE ((void*)0x65430000)
static
BOOL
HEAP_IsRealArena
(
HEAP
*
heapPtr
,
DWORD
flags
,
LPCVOID
block
,
BOOL
quiet
);
#ifdef __GNUC__
#define GET_EIP() (__builtin_return_address(0))
#define SET_EIP(ptr) ((ARENA_INUSE*)(ptr) - 1)->callerEIP = GET_EIP()
#else
#define GET_EIP() 0
#define SET_EIP(ptr)
/* nothing */
#endif
/* __GNUC__ */
/***********************************************************************
* HEAP_Dump
*/
void
HEAP_Dump
(
HEAP
*
heap
)
{
int
i
;
SUBHEAP
*
subheap
;
char
*
ptr
;
DPRINTF
(
"Heap: %08lx
\n
"
,
(
DWORD
)
heap
);
DPRINTF
(
"Next: %08lx Sub-heaps: %08lx"
,
(
DWORD
)
heap
->
next
,
(
DWORD
)
&
heap
->
subheap
);
subheap
=
&
heap
->
subheap
;
while
(
subheap
->
next
)
{
DPRINTF
(
" -> %08lx"
,
(
DWORD
)
subheap
->
next
);
subheap
=
subheap
->
next
;
}
DPRINTF
(
"
\n
Free lists:
\n
Block Stat Size Id
\n
"
);
for
(
i
=
0
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
)
DPRINTF
(
"%08lx free %08lx %04x prev=%08lx next=%08lx
\n
"
,
(
DWORD
)
&
heap
->
freeList
[
i
].
arena
,
heap
->
freeList
[
i
].
arena
.
size
,
heap
->
freeList
[
i
].
arena
.
threadId
,
(
DWORD
)
heap
->
freeList
[
i
].
arena
.
prev
,
(
DWORD
)
heap
->
freeList
[
i
].
arena
.
next
);
subheap
=
&
heap
->
subheap
;
while
(
subheap
)
{
DWORD
freeSize
=
0
,
usedSize
=
0
,
arenaSize
=
subheap
->
headerSize
;
DPRINTF
(
"
\n\n
Sub-heap %08lx: size=%08lx committed=%08lx
\n
"
,
(
DWORD
)
subheap
,
subheap
->
size
,
subheap
->
commitSize
);
DPRINTF
(
"
\n
Block Stat Size Id
\n
"
);
ptr
=
(
char
*
)
subheap
+
subheap
->
headerSize
;
while
(
ptr
<
(
char
*
)
subheap
+
subheap
->
size
)
{
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
ARENA_FREE
*
pArena
=
(
ARENA_FREE
*
)
ptr
;
DPRINTF
(
"%08lx free %08lx %04x prev=%08lx next=%08lx
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
,
pArena
->
threadId
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
->
next
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_FREE
);
freeSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
else
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_PREV_FREE
)
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DPRINTF
(
"%08lx Used %08lx %04x back=%08lx EIP=%p
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
,
pArena
->
threadId
,
*
((
DWORD
*
)
pArena
-
1
),
pArena
->
callerEIP
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_INUSE
);
usedSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DPRINTF
(
"%08lx used %08lx %04x EIP=%p
\n
"
,
(
DWORD
)
pArena
,
pArena
->
size
&
ARENA_SIZE_MASK
,
pArena
->
threadId
,
pArena
->
callerEIP
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_INUSE
);
usedSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
}
DPRINTF
(
"
\n
Total: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)
\n\n
"
,
subheap
->
size
,
subheap
->
commitSize
,
freeSize
,
usedSize
,
arenaSize
,
(
arenaSize
*
100
)
/
subheap
->
size
);
subheap
=
subheap
->
next
;
}
}
/***********************************************************************
* HEAP_GetPtr
* RETURNS
* Pointer to the heap
* NULL: Failure
*/
static
HEAP
*
HEAP_GetPtr
(
HANDLE
heap
/* [in] Handle to the heap */
)
{
HEAP
*
heapPtr
=
(
HEAP
*
)
heap
;
if
(
!
heapPtr
||
(
heapPtr
->
magic
!=
HEAP_MAGIC
))
{
ERR
(
"Invalid heap %08x!
\n
"
,
heap
);
SetLastError
(
ERROR_INVALID_HANDLE
);
return
NULL
;
}
if
(
TRACE_ON
(
heap
)
&&
!
HEAP_IsRealArena
(
heapPtr
,
0
,
NULL
,
NOISY
))
{
HEAP_Dump
(
heapPtr
);
assert
(
FALSE
);
SetLastError
(
ERROR_INVALID_HANDLE
);
return
NULL
;
}
return
heapPtr
;
}
/***********************************************************************
* HEAP_InsertFreeBlock
*
* Insert a free block into the free list.
*/
static
void
HEAP_InsertFreeBlock
(
HEAP
*
heap
,
ARENA_FREE
*
pArena
)
{
FREE_LIST_ENTRY
*
pEntry
=
heap
->
freeList
;
while
(
pEntry
->
size
<
pArena
->
size
)
pEntry
++
;
pArena
->
size
|=
ARENA_FLAG_FREE
;
pArena
->
next
=
pEntry
->
arena
.
next
;
pArena
->
next
->
prev
=
pArena
;
pArena
->
prev
=
&
pEntry
->
arena
;
pEntry
->
arena
.
next
=
pArena
;
}
/***********************************************************************
* HEAP_FindSubHeap
* Find the sub-heap containing a given address.
*
* RETURNS
* Pointer: Success
* NULL: Failure
*/
static
SUBHEAP
*
HEAP_FindSubHeap
(
HEAP
*
heap
,
/* [in] Heap pointer */
LPCVOID
ptr
/* [in] Address */
)
{
SUBHEAP
*
sub
=
&
heap
->
subheap
;
while
(
sub
)
{
if
(((
char
*
)
ptr
>=
(
char
*
)
sub
)
&&
((
char
*
)
ptr
<
(
char
*
)
sub
+
sub
->
size
))
return
sub
;
sub
=
sub
->
next
;
}
return
NULL
;
}
/***********************************************************************
* HEAP_Commit
*
* Make sure the heap storage is committed up to (not including) ptr.
*/
static
inline
BOOL
HEAP_Commit
(
SUBHEAP
*
subheap
,
void
*
ptr
)
{
DWORD
size
=
(
DWORD
)((
char
*
)
ptr
-
(
char
*
)
subheap
);
size
=
(
size
+
COMMIT_MASK
)
&
~
COMMIT_MASK
;
if
(
size
>
subheap
->
size
)
size
=
subheap
->
size
;
if
(
size
<=
subheap
->
commitSize
)
return
TRUE
;
if
(
!
VirtualAlloc
(
(
char
*
)
subheap
+
subheap
->
commitSize
,
size
-
subheap
->
commitSize
,
MEM_COMMIT
,
PAGE_EXECUTE_READWRITE
))
{
WARN
(
"Could not commit %08lx bytes at %08lx for heap %08lx
\n
"
,
size
-
subheap
->
commitSize
,
(
DWORD
)((
char
*
)
subheap
+
subheap
->
commitSize
),
(
DWORD
)
subheap
->
heap
);
return
FALSE
;
}
subheap
->
commitSize
=
size
;
return
TRUE
;
}
/***********************************************************************
* HEAP_Decommit
*
* If possible, decommit the heap storage from (including) 'ptr'.
*/
static
inline
BOOL
HEAP_Decommit
(
SUBHEAP
*
subheap
,
void
*
ptr
)
{
DWORD
size
=
(
DWORD
)((
char
*
)
ptr
-
(
char
*
)
subheap
);
/* round to next block and add one full block */
size
=
((
size
+
COMMIT_MASK
)
&
~
COMMIT_MASK
)
+
COMMIT_MASK
+
1
;
if
(
size
>=
subheap
->
commitSize
)
return
TRUE
;
if
(
!
VirtualFree
(
(
char
*
)
subheap
+
size
,
subheap
->
commitSize
-
size
,
MEM_DECOMMIT
))
{
WARN
(
"Could not decommit %08lx bytes at %08lx for heap %08lx
\n
"
,
subheap
->
commitSize
-
size
,
(
DWORD
)((
char
*
)
subheap
+
size
),
(
DWORD
)
subheap
->
heap
);
return
FALSE
;
}
subheap
->
commitSize
=
size
;
return
TRUE
;
}
/***********************************************************************
* HEAP_CreateFreeBlock
*
* Create a free block at a specified address. 'size' is the size of the
* whole block, including the new arena.
*/
static
void
HEAP_CreateFreeBlock
(
SUBHEAP
*
subheap
,
void
*
ptr
,
DWORD
size
)
{
ARENA_FREE
*
pFree
;
/* Create a free arena */
pFree
=
(
ARENA_FREE
*
)
ptr
;
pFree
->
threadId
=
GetCurrentTask
();
pFree
->
magic
=
ARENA_FREE_MAGIC
;
/* If debugging, erase the freed block content */
if
(
TRACE_ON
(
heap
))
{
char
*
pEnd
=
(
char
*
)
ptr
+
size
;
if
(
pEnd
>
(
char
*
)
subheap
+
subheap
->
commitSize
)
pEnd
=
(
char
*
)
subheap
+
subheap
->
commitSize
;
if
(
pEnd
>
(
char
*
)(
pFree
+
1
))
memset
(
pFree
+
1
,
ARENA_FREE_FILLER
,
pEnd
-
(
char
*
)(
pFree
+
1
)
);
}
/* Check if next block is free also */
if
(((
char
*
)
ptr
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
&&
(
*
(
DWORD
*
)((
char
*
)
ptr
+
size
)
&
ARENA_FLAG_FREE
))
{
/* Remove the next arena from the free list */
ARENA_FREE
*
pNext
=
(
ARENA_FREE
*
)((
char
*
)
ptr
+
size
);
pNext
->
next
->
prev
=
pNext
->
prev
;
pNext
->
prev
->
next
=
pNext
->
next
;
size
+=
(
pNext
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pNext
);
if
(
TRACE_ON
(
heap
))
memset
(
pNext
,
ARENA_FREE_FILLER
,
sizeof
(
ARENA_FREE
)
);
}
/* Set the next block PREV_FREE flag and pointer */
if
((
char
*
)
ptr
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
{
DWORD
*
pNext
=
(
DWORD
*
)((
char
*
)
ptr
+
size
);
*
pNext
|=
ARENA_FLAG_PREV_FREE
;
*
(
ARENA_FREE
**
)(
pNext
-
1
)
=
pFree
;
}
/* Last, insert the new block into the free list */
pFree
->
size
=
size
-
sizeof
(
*
pFree
);
HEAP_InsertFreeBlock
(
subheap
->
heap
,
pFree
);
}
/***********************************************************************
* HEAP_MakeInUseBlockFree
*
* Turn an in-use block into a free block. Can also decommit the end of
* the heap, and possibly even free the sub-heap altogether.
*/
static
void
HEAP_MakeInUseBlockFree
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
)
{
ARENA_FREE
*
pFree
;
DWORD
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pArena
);
/* Check if we can merge with previous block */
if
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
)
{
pFree
=
*
((
ARENA_FREE
**
)
pArena
-
1
);
size
+=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
);
/* Remove it from the free list */
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
}
else
pFree
=
(
ARENA_FREE
*
)
pArena
;
/* Create a free block */
HEAP_CreateFreeBlock
(
subheap
,
pFree
,
size
);
size
=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
);
if
((
char
*
)
pFree
+
size
<
(
char
*
)
subheap
+
subheap
->
size
)
return
;
/* Not the last block, so nothing more to do */
/* Free the whole sub-heap if it's empty and not the original one */
if
(((
char
*
)
pFree
==
(
char
*
)
subheap
+
subheap
->
headerSize
)
&&
(
subheap
!=
&
subheap
->
heap
->
subheap
))
{
SUBHEAP
*
pPrev
=
&
subheap
->
heap
->
subheap
;
/* Remove the free block from the list */
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
/* Remove the subheap from the list */
while
(
pPrev
&&
(
pPrev
->
next
!=
subheap
))
pPrev
=
pPrev
->
next
;
if
(
pPrev
)
pPrev
->
next
=
subheap
->
next
;
/* Free the memory */
subheap
->
magic
=
0
;
if
(
subheap
->
selector
)
FreeSelector16
(
subheap
->
selector
);
VirtualFree
(
subheap
,
0
,
MEM_RELEASE
);
return
;
}
/* Decommit the end of the heap */
if
(
!
(
subheap
->
heap
->
flags
&
HEAP_SHARED
))
HEAP_Decommit
(
subheap
,
pFree
+
1
);
}
/***********************************************************************
* HEAP_ShrinkBlock
*
* Shrink an in-use block.
*/
static
void
HEAP_ShrinkBlock
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
,
DWORD
size
)
{
if
((
pArena
->
size
&
ARENA_SIZE_MASK
)
>=
size
+
HEAP_MIN_BLOCK_SIZE
)
{
HEAP_CreateFreeBlock
(
subheap
,
(
char
*
)(
pArena
+
1
)
+
size
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
size
);
/* assign size plus previous arena flags */
pArena
->
size
=
size
|
(
pArena
->
size
&
~
ARENA_SIZE_MASK
);
}
else
{
/* Turn off PREV_FREE flag in next block */
char
*
pNext
=
(
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
if
(
pNext
<
(
char
*
)
subheap
+
subheap
->
size
)
*
(
DWORD
*
)
pNext
&=
~
ARENA_FLAG_PREV_FREE
;
}
}
/***********************************************************************
* HEAP_InitSubHeap
*/
static
BOOL
HEAP_InitSubHeap
(
HEAP
*
heap
,
LPVOID
address
,
DWORD
flags
,
DWORD
commitSize
,
DWORD
totalSize
)
{
SUBHEAP
*
subheap
=
(
SUBHEAP
*
)
address
;
WORD
selector
=
0
;
FREE_LIST_ENTRY
*
pEntry
;
int
i
;
/* Commit memory */
if
(
flags
&
HEAP_SHARED
)
commitSize
=
totalSize
;
/* always commit everything in a shared heap */
if
(
!
VirtualAlloc
(
address
,
commitSize
,
MEM_COMMIT
,
PAGE_EXECUTE_READWRITE
))
{
WARN
(
"Could not commit %08lx bytes for sub-heap %08lx
\n
"
,
commitSize
,
(
DWORD
)
address
);
return
FALSE
;
}
/* Allocate a selector if needed */
if
(
flags
&
HEAP_WINE_SEGPTR
)
{
unsigned
char
selflags
=
WINE_LDT_FLAGS_DATA
;
if
(
flags
&
(
HEAP_WINE_CODESEG
|
HEAP_WINE_CODE16SEG
))
selflags
=
WINE_LDT_FLAGS_CODE
;
if
(
flags
&
HEAP_WINE_CODESEG
)
selflags
|=
WINE_LDT_FLAGS_32BIT
;
selector
=
SELECTOR_AllocBlock
(
address
,
totalSize
,
selflags
);
if
(
!
selector
)
{
ERR
(
"Could not allocate selector
\n
"
);
return
FALSE
;
}
}
/* Fill the sub-heap structure */
subheap
->
heap
=
heap
;
subheap
->
selector
=
selector
;
subheap
->
size
=
totalSize
;
subheap
->
commitSize
=
commitSize
;
subheap
->
magic
=
SUBHEAP_MAGIC
;
if
(
subheap
!=
(
SUBHEAP
*
)
heap
)
{
/* If this is a secondary subheap, insert it into list */
subheap
->
headerSize
=
sizeof
(
SUBHEAP
);
subheap
->
next
=
heap
->
subheap
.
next
;
heap
->
subheap
.
next
=
subheap
;
}
else
{
/* If this is a primary subheap, initialize main heap */
subheap
->
headerSize
=
sizeof
(
HEAP
);
subheap
->
next
=
NULL
;
heap
->
next
=
NULL
;
heap
->
flags
=
flags
;
heap
->
magic
=
HEAP_MAGIC
;
/* Build the free lists */
for
(
i
=
0
,
pEntry
=
heap
->
freeList
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
,
pEntry
++
)
{
pEntry
->
size
=
HEAP_freeListSizes
[
i
];
pEntry
->
arena
.
size
=
0
|
ARENA_FLAG_FREE
;
pEntry
->
arena
.
next
=
i
<
HEAP_NB_FREE_LISTS
-
1
?
&
heap
->
freeList
[
i
+
1
].
arena
:
&
heap
->
freeList
[
0
].
arena
;
pEntry
->
arena
.
prev
=
i
?
&
heap
->
freeList
[
i
-
1
].
arena
:
&
heap
->
freeList
[
HEAP_NB_FREE_LISTS
-
1
].
arena
;
pEntry
->
arena
.
threadId
=
0
;
pEntry
->
arena
.
magic
=
ARENA_FREE_MAGIC
;
}
/* Initialize critical section */
InitializeCriticalSection
(
&
heap
->
critSection
);
}
/* Create the first free block */
HEAP_CreateFreeBlock
(
subheap
,
(
LPBYTE
)
subheap
+
subheap
->
headerSize
,
subheap
->
size
-
subheap
->
headerSize
);
return
TRUE
;
}
/***********************************************************************
* HEAP_CreateSubHeap
*
* Create a sub-heap of the given size.
* If heap == NULL, creates a main heap.
*/
static
SUBHEAP
*
HEAP_CreateSubHeap
(
HEAP
*
heap
,
DWORD
flags
,
DWORD
commitSize
,
DWORD
totalSize
)
{
LPVOID
address
;
/* Round-up sizes on a 64K boundary */
if
(
flags
&
HEAP_WINE_SEGPTR
)
{
totalSize
=
commitSize
=
0x10000
;
/* Only 64K at a time for SEGPTRs */
}
else
{
totalSize
=
(
totalSize
+
0xffff
)
&
0xffff0000
;
commitSize
=
(
commitSize
+
0xffff
)
&
0xffff0000
;
if
(
!
commitSize
)
commitSize
=
0x10000
;
if
(
totalSize
<
commitSize
)
totalSize
=
commitSize
;
}
/* Allocate the memory block */
if
(
!
(
address
=
VirtualAlloc
(
NULL
,
totalSize
,
MEM_RESERVE
,
PAGE_EXECUTE_READWRITE
)))
{
WARN
(
"Could not VirtualAlloc %08lx bytes
\n
"
,
totalSize
);
return
NULL
;
}
/* Initialize subheap */
if
(
!
HEAP_InitSubHeap
(
heap
?
heap
:
(
HEAP
*
)
address
,
address
,
flags
,
commitSize
,
totalSize
))
{
VirtualFree
(
address
,
0
,
MEM_RELEASE
);
return
NULL
;
}
return
(
SUBHEAP
*
)
address
;
}
/***********************************************************************
* HEAP_FindFreeBlock
*
* Find a free block at least as large as the requested size, and make sure
* the requested size is committed.
*/
static
ARENA_FREE
*
HEAP_FindFreeBlock
(
HEAP
*
heap
,
DWORD
size
,
SUBHEAP
**
ppSubHeap
)
{
SUBHEAP
*
subheap
;
ARENA_FREE
*
pArena
;
FREE_LIST_ENTRY
*
pEntry
=
heap
->
freeList
;
/* Find a suitable free list, and in it find a block large enough */
while
(
pEntry
->
size
<
size
)
pEntry
++
;
pArena
=
pEntry
->
arena
.
next
;
while
(
pArena
!=
&
heap
->
freeList
[
0
].
arena
)
{
DWORD
arena_size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
if
(
arena_size
>=
size
)
{
subheap
=
HEAP_FindSubHeap
(
heap
,
pArena
);
if
(
!
HEAP_Commit
(
subheap
,
(
char
*
)
pArena
+
sizeof
(
ARENA_INUSE
)
+
size
+
HEAP_MIN_BLOCK_SIZE
))
return
NULL
;
*
ppSubHeap
=
subheap
;
return
pArena
;
}
pArena
=
pArena
->
next
;
}
/* If no block was found, attempt to grow the heap */
if
(
!
(
heap
->
flags
&
HEAP_GROWABLE
))
{
WARN
(
"Not enough space in heap %08lx for %08lx bytes
\n
"
,
(
DWORD
)
heap
,
size
);
return
NULL
;
}
/* make sure that we have a big enough size *committed* to fit another
* last free arena in !
* So just one heap struct, one first free arena which will eventually
* get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
* might get assigned all remaining free space in HEAP_ShrinkBlock() */
size
+=
sizeof
(
SUBHEAP
)
+
sizeof
(
ARENA_INUSE
)
+
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
subheap
=
HEAP_CreateSubHeap
(
heap
,
heap
->
flags
,
size
,
max
(
HEAP_DEF_SIZE
,
size
)
)))
return
NULL
;
TRACE
(
"created new sub-heap %08lx of %08lx bytes for heap %08lx
\n
"
,
(
DWORD
)
subheap
,
size
,
(
DWORD
)
heap
);
*
ppSubHeap
=
subheap
;
return
(
ARENA_FREE
*
)(
subheap
+
1
);
}
/***********************************************************************
* HEAP_IsValidArenaPtr
*
* Check that the pointer is inside the range possible for arenas.
*/
static
BOOL
HEAP_IsValidArenaPtr
(
HEAP
*
heap
,
void
*
ptr
)
{
int
i
;
SUBHEAP
*
subheap
=
HEAP_FindSubHeap
(
heap
,
ptr
);
if
(
!
subheap
)
return
FALSE
;
if
((
char
*
)
ptr
>=
(
char
*
)
subheap
+
subheap
->
headerSize
)
return
TRUE
;
if
(
subheap
!=
&
heap
->
subheap
)
return
FALSE
;
for
(
i
=
0
;
i
<
HEAP_NB_FREE_LISTS
;
i
++
)
if
(
ptr
==
(
void
*
)
&
heap
->
freeList
[
i
].
arena
)
return
TRUE
;
return
FALSE
;
}
/***********************************************************************
* HEAP_ValidateFreeArena
*/
static
BOOL
HEAP_ValidateFreeArena
(
SUBHEAP
*
subheap
,
ARENA_FREE
*
pArena
)
{
char
*
heapEnd
=
(
char
*
)
subheap
+
subheap
->
size
;
#if !defined(ALLOW_UNALIGNED_ACCESS)
/* Check for unaligned pointers */
if
(
(
long
)
pArena
%
sizeof
(
void
*
)
!=
0
)
{
ERR
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
#endif
/* Check magic number */
if
(
pArena
->
magic
!=
ARENA_FREE_MAGIC
)
{
ERR
(
"Heap %08lx: invalid free arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check size flags */
if
(
!
(
pArena
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: bad flags %lx for free arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
pArena
->
size
&
~
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
}
/* Check arena size */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
>
heapEnd
)
{
ERR
(
"Heap %08lx: bad size %08lx for free arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
size
&
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next pointer is valid */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pArena
->
next
))
{
ERR
(
"Heap %08lx: bad next ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
next
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next arena is free */
if
(
!
(
pArena
->
next
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
next
->
magic
!=
ARENA_FREE_MAGIC
))
{
ERR
(
"Heap %08lx: next arena %08lx invalid for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
next
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev pointer is valid */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pArena
->
prev
))
{
ERR
(
"Heap %08lx: bad prev ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is free */
if
(
!
(
pArena
->
prev
->
size
&
ARENA_FLAG_FREE
)
||
(
pArena
->
prev
->
magic
!=
ARENA_FREE_MAGIC
))
{
/* this often means that the prev arena got overwritten
* by a memory write before that prev arena */
ERR
(
"Heap %08lx: prev arena %08lx invalid for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
prev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that next block has PREV_FREE flag */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
<
heapEnd
)
{
if
(
!
(
*
(
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: free arena %08lx next block has no PREV_FREE flag
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check next block back pointer */
if
(
*
((
ARENA_FREE
**
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
-
1
)
!=
pArena
)
{
ERR
(
"Heap %08lx: arena %08lx has wrong back ptr %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
,
*
((
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
-
1
));
return
FALSE
;
}
}
return
TRUE
;
}
/***********************************************************************
* HEAP_ValidateInUseArena
*/
static
BOOL
HEAP_ValidateInUseArena
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
,
BOOL
quiet
)
{
char
*
heapEnd
=
(
char
*
)
subheap
+
subheap
->
size
;
#if !defined(ALLOW_UNALIGNED_ACCESS)
/* Check for unaligned pointers */
if
(
(
long
)
pArena
%
sizeof
(
void
*
)
!=
0
)
{
if
(
quiet
==
NOISY
)
{
ERR
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
)
)
HEAP_Dump
(
subheap
->
heap
);
}
else
if
(
WARN_ON
(
heap
)
)
{
WARN
(
"Heap %08lx: unaligned arena pointer %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
)
)
HEAP_Dump
(
subheap
->
heap
);
}
return
FALSE
;
}
#endif
/* Check magic number */
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
)
{
if
(
quiet
==
NOISY
)
{
ERR
(
"Heap %08lx: invalid in-use arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
))
HEAP_Dump
(
subheap
->
heap
);
}
else
if
(
WARN_ON
(
heap
))
{
WARN
(
"Heap %08lx: invalid in-use arena magic for %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
if
(
TRACE_ON
(
heap
))
HEAP_Dump
(
subheap
->
heap
);
}
return
FALSE
;
}
/* Check size flags */
if
(
pArena
->
size
&
ARENA_FLAG_FREE
)
{
ERR
(
"Heap %08lx: bad flags %lx for in-use arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
pArena
->
size
&
~
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
}
/* Check arena size */
if
((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
>
heapEnd
)
{
ERR
(
"Heap %08lx: bad size %08lx for in-use arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
->
size
&
ARENA_SIZE_MASK
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check next arena PREV_FREE flag */
if
(((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
)
<
heapEnd
)
&&
(
*
(
DWORD
*
)((
char
*
)(
pArena
+
1
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
))
&
ARENA_FLAG_PREV_FREE
))
{
ERR
(
"Heap %08lx: in-use arena %08lx next block has PREV_FREE flag
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check prev free arena */
if
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
)
{
ARENA_FREE
*
pPrev
=
*
((
ARENA_FREE
**
)
pArena
-
1
);
/* Check prev pointer */
if
(
!
HEAP_IsValidArenaPtr
(
subheap
->
heap
,
pPrev
))
{
ERR
(
"Heap %08lx: bad back ptr %08lx for arena %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is free */
if
(
!
(
pPrev
->
size
&
ARENA_FLAG_FREE
)
||
(
pPrev
->
magic
!=
ARENA_FREE_MAGIC
))
{
ERR
(
"Heap %08lx: prev arena %08lx invalid for in-use %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
/* Check that prev arena is really the previous block */
if
((
char
*
)(
pPrev
+
1
)
+
(
pPrev
->
size
&
ARENA_SIZE_MASK
)
!=
(
char
*
)
pArena
)
{
ERR
(
"Heap %08lx: prev arena %08lx is not prev for in-use %08lx
\n
"
,
(
DWORD
)
subheap
->
heap
,
(
DWORD
)
pPrev
,
(
DWORD
)
pArena
);
return
FALSE
;
}
}
return
TRUE
;
}
/***********************************************************************
* HEAP_GetSegptr
*
* Transform a linear pointer into a SEGPTR. The pointer must have been
* allocated from a HEAP_WINE_SEGPTR heap.
*/
SEGPTR
HEAP_GetSegptr
(
HANDLE
heap
,
DWORD
flags
,
LPCVOID
ptr
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
SUBHEAP
*
subheap
;
SEGPTR
ret
=
0
;
/* Validate the parameters */
if
(
!
heapPtr
)
return
0
;
flags
|=
heapPtr
->
flags
;
if
(
!
(
flags
&
HEAP_WINE_SEGPTR
))
{
ERR
(
"Heap %08x is not a SEGPTR heap
\n
"
,
heap
);
return
0
;
}
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
/* Get the subheap */
if
((
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
ptr
)))
ret
=
MAKESEGPTR
(
subheap
->
selector
,
(
char
*
)
ptr
-
(
char
*
)
subheap
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
/***********************************************************************
* MapLS (KERNEL32.@)
* MapLS (KERNEL.358)
*
* Maps linear pointer to segmented.
*/
SEGPTR
WINAPI
MapLS
(
LPCVOID
ptr
)
{
SUBHEAP
*
subheap
;
SEGPTR
ret
=
0
;
if
(
!
HIWORD
(
ptr
))
return
(
SEGPTR
)
ptr
;
#include "winbase.h"
#include "wine/winbase16.h"
#include "winerror.h"
#include "winnt.h"
#include "ntddk.h"
#include "wine/unicode.h"
#include "selectors.h"
#include "global.h"
#include "thread.h"
#include "toolhelp.h"
#include "debugtools.h"
/* check if the pointer is inside the segptr heap */
EnterCriticalSection
(
&
segptrHeap
->
critSection
);
if
((
subheap
=
HEAP_FindSubHeap
(
segptrHeap
,
ptr
)))
ret
=
MAKESEGPTR
(
subheap
->
selector
,
(
char
*
)
ptr
-
(
char
*
)
subheap
);
LeaveCriticalSection
(
&
segptrHeap
->
critSection
);
DEFAULT_DEBUG_CHANNEL
(
heap
);
/* otherwise, allocate a brand-new selector */
if
(
!
ret
)
{
WORD
sel
=
SELECTOR_AllocBlock
(
ptr
,
0x10000
,
WINE_LDT_FLAGS_DATA
);
ret
=
MAKESEGPTR
(
sel
,
0
);
}
return
ret
;
}
/* address where we try to map the system heap */
#define SYSTEM_HEAP_BASE ((void*)0x65430000)
#define SYSTEM_HEAP_SIZE 0x100000
/* Default heap size = 1Mb */
/***********************************************************************
* UnMapLS (KERNEL32.@)
* UnMapLS (KERNEL.359)
*
* Free mapped selector.
*/
void
WINAPI
UnMapLS
(
SEGPTR
sptr
)
{
SUBHEAP
*
subheap
;
if
(
!
SELECTOROF
(
sptr
))
return
;
/* check if ptr is inside segptr heap */
EnterCriticalSection
(
&
segptrHeap
->
critSection
);
subheap
=
HEAP_FindSubHeap
(
segptrHeap
,
MapSL
(
sptr
)
);
if
((
subheap
)
&&
(
subheap
->
selector
!=
SELECTOROF
(
sptr
)))
subheap
=
NULL
;
LeaveCriticalSection
(
&
segptrHeap
->
critSection
);
/* if not inside heap, free the selector */
if
(
!
subheap
)
FreeSelector16
(
SELECTOROF
(
sptr
)
);
}
#define HTABLE_SIZE 0x10000
#define HTABLE_PAGESIZE 0x1000
#define HTABLE_NPAGES (HTABLE_SIZE / HTABLE_PAGESIZE)
/***********************************************************************
* HEAP_IsRealArena [Internal]
* Validates a block is a valid arena.
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
static
BOOL
HEAP_IsRealArena
(
HEAP
*
heapPtr
,
/* [in] ptr to the heap */
DWORD
flags
,
/* [in] Bit flags that control access during operation */
LPCVOID
block
,
/* [in] Optional pointer to memory block to validate */
BOOL
quiet
)
/* [in] Flag - if true, HEAP_ValidateInUseArena
* does not complain */
#include "pshpack1.h"
typedef
struct
_LOCAL32HEADER
{
SUBHEAP
*
subheap
;
BOOL
ret
=
TRUE
;
WORD
freeListFirst
[
HTABLE_NPAGES
];
WORD
freeListSize
[
HTABLE_NPAGES
];
WORD
freeListLast
[
HTABLE_NPAGES
];
if
(
!
heapPtr
||
(
heapPtr
->
magic
!=
HEAP_MAGIC
))
{
ERR
(
"Invalid heap %p!
\n
"
,
heapPtr
);
return
FALSE
;
}
DWORD
selectorTableOffset
;
WORD
selectorTableSize
;
WORD
selectorDelta
;
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
/* calling HeapLock may result in infinite recursion, so do the critsect directly */
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
DWORD
segment
;
LPBYTE
base
;
if
(
block
)
{
/* Only check this single memory block */
DWORD
limit
;
DWORD
flags
;
if
(
!
(
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
block
))
||
((
char
*
)
block
<
(
char
*
)
subheap
+
subheap
->
headerSize
+
sizeof
(
ARENA_INUSE
)))
{
if
(
quiet
==
NOISY
)
ERR
(
"Heap %p: block %p is not inside heap
\n
"
,
heapPtr
,
block
);
else
if
(
WARN_ON
(
heap
))
WARN
(
"Heap %p: block %p is not inside heap
\n
"
,
heapPtr
,
block
);
ret
=
FALSE
;
}
else
ret
=
HEAP_ValidateInUseArena
(
subheap
,
(
ARENA_INUSE
*
)
block
-
1
,
quiet
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
DWORD
magic
;
HANDLE
heap
;
subheap
=
&
heapPtr
->
subheap
;
while
(
subheap
&&
ret
)
{
char
*
ptr
=
(
char
*
)
subheap
+
subheap
->
headerSize
;
while
(
ptr
<
(
char
*
)
subheap
+
subheap
->
size
)
{
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
if
(
!
HEAP_ValidateFreeArena
(
subheap
,
(
ARENA_FREE
*
)
ptr
))
{
ret
=
FALSE
;
break
;
}
ptr
+=
sizeof
(
ARENA_FREE
)
+
(
*
(
DWORD
*
)
ptr
&
ARENA_SIZE_MASK
);
}
else
{
if
(
!
HEAP_ValidateInUseArena
(
subheap
,
(
ARENA_INUSE
*
)
ptr
,
NOISY
))
{
ret
=
FALSE
;
break
;
}
ptr
+=
sizeof
(
ARENA_INUSE
)
+
(
*
(
DWORD
*
)
ptr
&
ARENA_SIZE_MASK
);
}
}
subheap
=
subheap
->
next
;
}
}
LOCAL32HEADER
;
#include "poppack.h"
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
}
#define LOCAL32_MAGIC ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
static
HANDLE
systemHeap
;
/* globally shared heap */
/***********************************************************************
* HEAP_CreateSystemHeap
*
* Create the system heap.
*/
static
HANDLE
HEAP_CreateSystemHeap
(
void
)
inline
static
HANDLE
HEAP_CreateSystemHeap
(
void
)
{
int
created
;
void
*
base
;
HANDLE
map
,
event
;
UNICODE_STRING
event_name
;
OBJECT_ATTRIBUTES
event_attr
;
HANDLE
map
=
CreateFileMappingA
(
INVALID_HANDLE_VALUE
,
NULL
,
SEC_COMMIT
|
PAGE_READWRITE
,
0
,
HEAP_DEF_SIZE
,
"__SystemHeap"
);
if
(
!
map
)
return
0
;
if
(
!
(
map
=
CreateFileMappingA
(
INVALID_HANDLE_VALUE
,
NULL
,
SEC_COMMIT
|
PAGE_READWRITE
,
0
,
SYSTEM_HEAP_SIZE
,
"__SystemHeap"
)))
return
0
;
created
=
(
GetLastError
()
!=
ERROR_ALREADY_EXISTS
);
if
(
!
(
systemHeap
=
MapViewOfFileEx
(
map
,
FILE_MAP_ALL_ACCESS
,
0
,
0
,
0
,
SYSTEM_HEAP_BASE
)))
if
(
!
(
base
=
MapViewOfFileEx
(
map
,
FILE_MAP_ALL_ACCESS
,
0
,
0
,
0
,
SYSTEM_HEAP_BASE
)))
{
/* pre-defined address not available
, use any one
*/
/* pre-defined address not available */
ERR
(
"system heap base address %p not available
\n
"
,
SYSTEM_HEAP_BASE
);
return
0
;
}
/* create the system heap event */
RtlCreateUnicodeStringFromAsciiz
(
&
event_name
,
"__SystemHeapEvent"
);
event_attr
.
Length
=
sizeof
(
event_attr
);
event_attr
.
RootDirectory
=
0
;
event_attr
.
ObjectName
=
&
event_name
;
event_attr
.
Attributes
=
0
;
event_attr
.
SecurityDescriptor
=
NULL
;
event_attr
.
SecurityQualityOfService
=
NULL
;
NtCreateEvent
(
&
event
,
EVENT_ALL_ACCESS
,
&
event_attr
,
TRUE
,
FALSE
);
if
(
created
)
/* newly created heap */
{
HEAP_InitSubHeap
(
systemHeap
,
systemHeap
,
HEAP_SHARED
,
0
,
HEAP_DEF_SIZE
);
MakeCriticalSectionGlobal
(
&
systemHeap
->
critSection
);
systemHeap
=
RtlCreateHeap
(
HEAP_SHARED
,
base
,
SYSTEM_HEAP_SIZE
,
SYSTEM_HEAP_SIZE
,
NULL
,
NULL
);
NtSetEvent
(
event
,
NULL
);
}
else
{
/* wait for the heap to be initialized */
while
(
!
systemHeap
->
critSection
.
LockSemaphore
)
Sleep
(
1
);
WaitForSingleObject
(
event
,
INFINITE
);
}
CloseHandle
(
map
);
return
(
HANDLE
)
systemHeap
;
return
systemHeap
;
}
...
...
@@ -1076,49 +123,20 @@ HANDLE WINAPI HeapCreate(
DWORD
initialSize
,
/* [in] Initial heap size */
DWORD
maxSize
/* [in] Maximum heap size */
)
{
SUBHEAP
*
subheap
;
HANDLE
ret
;
if
(
flags
&
HEAP_SHARED
)
{
if
(
flags
&
HEAP_SHARED
)
{
if
(
!
systemHeap
)
HEAP_CreateSystemHeap
();
else
WARN
(
"Shared Heap requested, returning system heap.
\n
"
);
return
(
HANDLE
)
systemHeap
;
}
/* Allocate the heap block */
if
(
!
maxSize
)
{
maxSize
=
HEAP_DEF_SIZE
;
flags
|=
HEAP_GROWABLE
;
ret
=
systemHeap
;
}
if
(
!
(
subheap
=
HEAP_CreateSubHeap
(
NULL
,
flags
,
initialSize
,
maxSize
)))
{
SetLastError
(
ERROR_OUTOFMEMORY
);
return
0
;
}
/* link it into the per-process heap list */
if
(
processHeap
)
{
HEAP
*
heapPtr
=
subheap
->
heap
;
EnterCriticalSection
(
&
processHeap
->
critSection
);
heapPtr
->
next
=
firstHeap
;
firstHeap
=
heapPtr
;
LeaveCriticalSection
(
&
processHeap
->
critSection
);
}
else
/* assume the first heap we create is the process main heap */
else
{
SUBHEAP
*
segptr
;
processHeap
=
subheap
->
heap
;
/* create the SEGPTR heap */
if
(
!
(
segptr
=
HEAP_CreateSubHeap
(
NULL
,
flags
|
HEAP_WINE_SEGPTR
|
HEAP_GROWABLE
,
0
,
0
)))
{
SetLastError
(
ERROR_OUTOFMEMORY
);
return
0
;
}
segptrHeap
=
segptr
->
heap
;
ret
=
RtlCreateHeap
(
flags
,
NULL
,
maxSize
,
initialSize
,
NULL
,
NULL
);
if
(
!
ret
)
SetLastError
(
ERROR_NOT_ENOUGH_MEMORY
);
}
return
(
HANDLE
)
subheap
;
return
ret
;
}
/***********************************************************************
...
...
@@ -1129,284 +147,14 @@ HANDLE WINAPI HeapCreate(
*/
BOOL
WINAPI
HeapDestroy
(
HANDLE
heap
/* [in] Handle of heap */
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
SUBHEAP
*
subheap
;
TRACE
(
"%08x
\n
"
,
heap
);
if
(
!
heapPtr
)
return
FALSE
;
if
(
heapPtr
==
systemHeap
)
if
(
heap
==
systemHeap
)
{
WARN
(
"attempt to destroy system heap, returning TRUE!
\n
"
);
return
TRUE
;
}
if
(
heapPtr
==
processHeap
)
/* cannot delete the main process heap */
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
FALSE
;
}
else
/* remove it from the per-process list */
{
HEAP
**
pptr
;
EnterCriticalSection
(
&
processHeap
->
critSection
);
pptr
=
&
firstHeap
;
while
(
*
pptr
&&
*
pptr
!=
heapPtr
)
pptr
=
&
(
*
pptr
)
->
next
;
if
(
*
pptr
)
*
pptr
=
(
*
pptr
)
->
next
;
LeaveCriticalSection
(
&
processHeap
->
critSection
);
}
DeleteCriticalSection
(
&
heapPtr
->
critSection
);
subheap
=
&
heapPtr
->
subheap
;
while
(
subheap
)
{
SUBHEAP
*
next
=
subheap
->
next
;
if
(
subheap
->
selector
)
FreeSelector16
(
subheap
->
selector
);
VirtualFree
(
subheap
,
0
,
MEM_RELEASE
);
subheap
=
next
;
}
return
TRUE
;
}
/***********************************************************************
* HeapAlloc (KERNEL32.@)
* RETURNS
* Pointer to allocated memory block
* NULL: Failure
*/
LPVOID
WINAPI
HeapAlloc
(
HANDLE
heap
,
/* [in] Handle of private heap block */
DWORD
flags
,
/* [in] Heap allocation control flags */
DWORD
size
/* [in] Number of bytes to allocate */
)
{
ARENA_FREE
*
pArena
;
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
subheap
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
/* Validate the parameters */
if
((
flags
&
HEAP_WINE_SEGPTR
)
&&
size
<
0x10000
)
heapPtr
=
segptrHeap
;
if
(
!
heapPtr
)
return
NULL
;
flags
&=
HEAP_GENERATE_EXCEPTIONS
|
HEAP_NO_SERIALIZE
|
HEAP_ZERO_MEMORY
;
flags
|=
heapPtr
->
flags
;
size
=
(
size
+
3
)
&
~
3
;
if
(
size
<
HEAP_MIN_BLOCK_SIZE
)
size
=
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
/* Locate a suitable free block */
if
(
!
(
pArena
=
HEAP_FindFreeBlock
(
heapPtr
,
size
,
&
subheap
)))
{
TRACE
(
"(%08x,%08lx,%08lx): returning NULL
\n
"
,
heap
,
flags
,
size
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
SetLastError
(
ERROR_COMMITMENT_LIMIT
);
return
NULL
;
}
/* Remove the arena from the free list */
pArena
->
next
->
prev
=
pArena
->
prev
;
pArena
->
prev
->
next
=
pArena
->
next
;
/* Build the in-use arena */
pInUse
=
(
ARENA_INUSE
*
)
pArena
;
/* in-use arena is smaller than free arena,
* so we have to add the difference to the size */
pInUse
->
size
=
(
pInUse
->
size
&
~
ARENA_FLAG_FREE
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
pInUse
->
callerEIP
=
GET_EIP
();
pInUse
->
threadId
=
GetCurrentTask
();
pInUse
->
magic
=
ARENA_INUSE_MAGIC
;
/* Shrink the block */
HEAP_ShrinkBlock
(
subheap
,
pInUse
,
size
);
if
(
flags
&
HEAP_ZERO_MEMORY
)
memset
(
pInUse
+
1
,
0
,
pInUse
->
size
&
ARENA_SIZE_MASK
);
else
if
(
TRACE_ON
(
heap
))
memset
(
pInUse
+
1
,
ARENA_INUSE_FILLER
,
pInUse
->
size
&
ARENA_SIZE_MASK
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
size
,
(
DWORD
)(
pInUse
+
1
)
);
return
(
LPVOID
)(
pInUse
+
1
);
}
/***********************************************************************
* HeapFree (KERNEL32.@)
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL
WINAPI
HeapFree
(
HANDLE
heap
,
/* [in] Handle of heap */
DWORD
flags
,
/* [in] Heap freeing flags */
LPVOID
ptr
/* [in] Address of memory to free */
)
{
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
subheap
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
/* Validate the parameters */
if
(
!
ptr
)
return
TRUE
;
/* freeing a NULL ptr isn't an error in Win2k */
if
(
flags
&
HEAP_WINE_SEGPTR
)
heapPtr
=
segptrHeap
;
if
(
!
heapPtr
)
return
FALSE
;
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
SetLastError
(
ERROR_INVALID_PARAMETER
);
TRACE
(
"(%08x,%08lx,%08lx): returning FALSE
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
);
return
FALSE
;
}
/* Turn the block into a free block */
pInUse
=
(
ARENA_INUSE
*
)
ptr
-
1
;
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
pInUse
);
HEAP_MakeInUseBlockFree
(
subheap
,
pInUse
);
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning TRUE
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
);
return
TRUE
;
}
/***********************************************************************
* HeapReAlloc (KERNEL32.@)
* RETURNS
* Pointer to reallocated memory block
* NULL: Failure
*/
LPVOID
WINAPI
HeapReAlloc
(
HANDLE
heap
,
/* [in] Handle of heap block */
DWORD
flags
,
/* [in] Heap reallocation flags */
LPVOID
ptr
,
/* [in] Address of memory to reallocate */
DWORD
size
/* [in] Number of bytes to reallocate */
)
{
ARENA_INUSE
*
pArena
;
DWORD
oldSize
;
HEAP
*
heapPtr
;
SUBHEAP
*
subheap
;
if
(
!
ptr
)
return
HeapAlloc
(
heap
,
flags
,
size
);
/* FIXME: correct? */
if
((
flags
&
HEAP_WINE_SEGPTR
)
&&
size
<
0x10000
)
heapPtr
=
segptrHeap
;
if
(
!
(
heapPtr
=
HEAP_GetPtr
(
heap
)))
return
FALSE
;
/* Validate the parameters */
flags
&=
HEAP_GENERATE_EXCEPTIONS
|
HEAP_NO_SERIALIZE
|
HEAP_ZERO_MEMORY
|
HEAP_REALLOC_IN_PLACE_ONLY
;
flags
|=
heapPtr
->
flags
;
size
=
(
size
+
3
)
&
~
3
;
if
(
size
<
HEAP_MIN_BLOCK_SIZE
)
size
=
HEAP_MIN_BLOCK_SIZE
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
SetLastError
(
ERROR_INVALID_PARAMETER
);
TRACE
(
"(%08x,%08lx,%08lx,%08lx): returning NULL
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
size
);
return
NULL
;
}
/* Check if we need to grow the block */
pArena
=
(
ARENA_INUSE
*
)
ptr
-
1
;
pArena
->
threadId
=
GetCurrentTask
();
subheap
=
HEAP_FindSubHeap
(
heapPtr
,
pArena
);
oldSize
=
(
pArena
->
size
&
ARENA_SIZE_MASK
);
if
(
size
>
oldSize
)
{
char
*
pNext
=
(
char
*
)(
pArena
+
1
)
+
oldSize
;
if
((
pNext
<
(
char
*
)
subheap
+
subheap
->
size
)
&&
(
*
(
DWORD
*
)
pNext
&
ARENA_FLAG_FREE
)
&&
(
oldSize
+
(
*
(
DWORD
*
)
pNext
&
ARENA_SIZE_MASK
)
+
sizeof
(
ARENA_FREE
)
>=
size
))
{
/* The next block is free and large enough */
ARENA_FREE
*
pFree
=
(
ARENA_FREE
*
)
pNext
;
pFree
->
next
->
prev
=
pFree
->
prev
;
pFree
->
prev
->
next
=
pFree
->
next
;
pArena
->
size
+=
(
pFree
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pFree
);
if
(
!
HEAP_Commit
(
subheap
,
(
char
*
)
pArena
+
sizeof
(
ARENA_INUSE
)
+
size
+
HEAP_MIN_BLOCK_SIZE
))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
SetLastError
(
ERROR_OUTOFMEMORY
);
return
NULL
;
}
HEAP_ShrinkBlock
(
subheap
,
pArena
,
size
);
}
else
/* Do it the hard way */
{
ARENA_FREE
*
pNew
;
ARENA_INUSE
*
pInUse
;
SUBHEAP
*
newsubheap
;
if
((
flags
&
HEAP_REALLOC_IN_PLACE_ONLY
)
||
!
(
pNew
=
HEAP_FindFreeBlock
(
heapPtr
,
size
,
&
newsubheap
)))
{
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
SetLastError
(
ERROR_OUTOFMEMORY
);
return
NULL
;
}
/* Build the in-use arena */
pNew
->
next
->
prev
=
pNew
->
prev
;
pNew
->
prev
->
next
=
pNew
->
next
;
pInUse
=
(
ARENA_INUSE
*
)
pNew
;
pInUse
->
size
=
(
pInUse
->
size
&
~
ARENA_FLAG_FREE
)
+
sizeof
(
ARENA_FREE
)
-
sizeof
(
ARENA_INUSE
);
pInUse
->
threadId
=
GetCurrentTask
();
pInUse
->
magic
=
ARENA_INUSE_MAGIC
;
HEAP_ShrinkBlock
(
newsubheap
,
pInUse
,
size
);
memcpy
(
pInUse
+
1
,
pArena
+
1
,
oldSize
);
/* Free the previous block */
HEAP_MakeInUseBlockFree
(
subheap
,
pArena
);
subheap
=
newsubheap
;
pArena
=
pInUse
;
}
}
else
HEAP_ShrinkBlock
(
subheap
,
pArena
,
size
);
/* Shrink the block */
/* Clear the extra bytes if needed */
if
(
size
>
oldSize
)
{
if
(
flags
&
HEAP_ZERO_MEMORY
)
memset
(
(
char
*
)(
pArena
+
1
)
+
oldSize
,
0
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
oldSize
);
else
if
(
TRACE_ON
(
heap
))
memset
(
(
char
*
)(
pArena
+
1
)
+
oldSize
,
ARENA_INUSE_FILLER
,
(
pArena
->
size
&
ARENA_SIZE_MASK
)
-
oldSize
);
}
/* Return the new arena */
pArena
->
callerEIP
=
GET_EIP
();
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
size
,
(
DWORD
)(
pArena
+
1
)
);
return
(
LPVOID
)(
pArena
+
1
);
if
(
!
RtlDestroyHeap
(
heap
))
return
TRUE
;
SetLastError
(
ERROR_INVALID_HANDLE
);
return
FALSE
;
}
...
...
@@ -1415,8 +163,7 @@ LPVOID WINAPI HeapReAlloc(
*/
DWORD
WINAPI
HeapCompact
(
HANDLE
heap
,
DWORD
flags
)
{
SetLastError
(
ERROR_CALL_NOT_IMPLEMENTED
);
return
0
;
return
RtlCompactHeap
(
heap
,
flags
);
}
...
...
@@ -1431,10 +178,7 @@ DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
BOOL
WINAPI
HeapLock
(
HANDLE
heap
/* [in] Handle of heap to lock for exclusive access */
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
return
FALSE
;
EnterCriticalSection
(
&
heapPtr
->
critSection
);
return
TRUE
;
return
RtlLockHeap
(
heap
);
}
...
...
@@ -1449,47 +193,7 @@ BOOL WINAPI HeapLock(
BOOL
WINAPI
HeapUnlock
(
HANDLE
heap
/* [in] Handle to the heap to unlock */
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
!
heapPtr
)
return
FALSE
;
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
TRUE
;
}
/***********************************************************************
* HeapSize (KERNEL32.@)
* RETURNS
* Size in bytes of allocated memory
* 0xffffffff: Failure
*/
DWORD
WINAPI
HeapSize
(
HANDLE
heap
,
/* [in] Handle of heap */
DWORD
flags
,
/* [in] Heap size control flags */
LPVOID
ptr
/* [in] Address of memory to return size for */
)
{
DWORD
ret
;
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
flags
&
HEAP_WINE_SEGPTR
)
heapPtr
=
segptrHeap
;
if
(
!
heapPtr
)
return
FALSE
;
flags
&=
HEAP_NO_SERIALIZE
;
flags
|=
heapPtr
->
flags
;
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
if
(
!
HEAP_IsRealArena
(
heapPtr
,
HEAP_NO_SERIALIZE
,
ptr
,
QUIET
))
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
ret
=
0xffffffff
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
-
1
;
ret
=
pArena
->
size
&
ARENA_SIZE_MASK
;
}
if
(
!
(
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
TRACE
(
"(%08x,%08lx,%08lx): returning %08lx
\n
"
,
heap
,
flags
,
(
DWORD
)
ptr
,
ret
);
return
ret
;
return
RtlUnlockHeap
(
heap
);
}
...
...
@@ -1509,17 +213,13 @@ BOOL WINAPI HeapValidate(
DWORD
flags
,
/* [in] Bit flags that control access during operation */
LPCVOID
block
/* [in] Optional pointer to memory block to validate */
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
if
(
flags
&
HEAP_WINE_SEGPTR
)
heapPtr
=
segptrHeap
;
if
(
!
heapPtr
)
return
FALSE
;
return
HEAP_IsRealArena
(
heapPtr
,
flags
,
block
,
QUIET
);
return
RtlValidateHeap
(
heap
,
flags
,
block
);
}
/***********************************************************************
* HeapWalk (KERNEL32.@)
* Enumerates the memory blocks in a specified heap.
* See HEAP_Dump() for info on heap structure.
*
* TODO
* - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
...
...
@@ -1533,110 +233,9 @@ BOOL WINAPI HeapWalk(
HANDLE
heap
,
/* [in] Handle to heap to enumerate */
LPPROCESS_HEAP_ENTRY
entry
/* [out] Pointer to structure of enumeration info */
)
{
HEAP
*
heapPtr
=
HEAP_GetPtr
(
heap
);
SUBHEAP
*
sub
,
*
currentheap
=
NULL
;
BOOL
ret
=
FALSE
;
char
*
ptr
;
int
region_index
=
0
;
if
(
!
heapPtr
||
!
entry
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
FALSE
;
}
if
(
!
(
heapPtr
->
flags
&
HEAP_NO_SERIALIZE
))
EnterCriticalSection
(
&
heapPtr
->
critSection
);
/* set ptr to the next arena to be examined */
if
(
!
entry
->
lpData
)
/* first call (init) ? */
{
TRACE
(
"begin walking of heap 0x%08x.
\n
"
,
heap
);
/*HEAP_Dump(heapPtr);*/
currentheap
=
&
heapPtr
->
subheap
;
ptr
=
(
char
*
)
currentheap
+
currentheap
->
headerSize
;
}
else
{
ptr
=
entry
->
lpData
;
sub
=
&
heapPtr
->
subheap
;
while
(
sub
)
{
if
(((
char
*
)
ptr
>=
(
char
*
)
sub
)
&&
((
char
*
)
ptr
<
(
char
*
)
sub
+
sub
->
size
))
{
currentheap
=
sub
;
break
;
}
sub
=
sub
->
next
;
region_index
++
;
}
if
(
currentheap
==
NULL
)
{
ERR
(
"no matching subheap found, shouldn't happen !
\n
"
);
SetLastError
(
ERROR_NO_MORE_ITEMS
);
goto
HW_end
;
}
ptr
+=
entry
->
cbData
;
/* point to next arena */
if
(
ptr
>
(
char
*
)
currentheap
+
currentheap
->
size
-
1
)
{
/* proceed with next subheap */
if
(
!
(
currentheap
=
currentheap
->
next
))
{
/* successfully finished */
TRACE
(
"end reached.
\n
"
);
SetLastError
(
ERROR_NO_MORE_ITEMS
);
goto
HW_end
;
}
ptr
=
(
char
*
)
currentheap
+
currentheap
->
headerSize
;
}
}
entry
->
wFlags
=
0
;
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
{
ARENA_FREE
*
pArena
=
(
ARENA_FREE
*
)
ptr
;
/*TRACE("free, magic: %04x\n", pArena->magic);*/
entry
->
lpData
=
pArena
+
1
;
entry
->
cbData
=
pArena
->
size
&
ARENA_SIZE_MASK
;
entry
->
cbOverhead
=
sizeof
(
ARENA_FREE
);
entry
->
wFlags
=
PROCESS_HEAP_UNCOMMITTED_RANGE
;
}
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
/*TRACE("busy, magic: %04x\n", pArena->magic);*/
entry
->
lpData
=
pArena
+
1
;
entry
->
cbData
=
pArena
->
size
&
ARENA_SIZE_MASK
;
entry
->
cbOverhead
=
sizeof
(
ARENA_INUSE
);
entry
->
wFlags
=
PROCESS_HEAP_ENTRY_BUSY
;
/* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
and PROCESS_HEAP_ENTRY_DDESHARE yet */
}
entry
->
iRegionIndex
=
region_index
;
/* first element of heap ? */
if
(
ptr
==
(
char
*
)(
currentheap
+
currentheap
->
headerSize
))
{
entry
->
wFlags
|=
PROCESS_HEAP_REGION
;
entry
->
u
.
Region
.
dwCommittedSize
=
currentheap
->
commitSize
;
entry
->
u
.
Region
.
dwUnCommittedSize
=
currentheap
->
size
-
currentheap
->
commitSize
;
entry
->
u
.
Region
.
lpFirstBlock
=
/* first valid block */
currentheap
+
currentheap
->
headerSize
;
entry
->
u
.
Region
.
lpLastBlock
=
/* first invalid block */
currentheap
+
currentheap
->
size
;
}
ret
=
TRUE
;
HW_end
:
if
(
!
(
heapPtr
->
flags
&
HEAP_NO_SERIALIZE
))
LeaveCriticalSection
(
&
heapPtr
->
critSection
);
return
ret
;
NTSTATUS
ret
=
RtlWalkHeap
(
heap
,
entry
);
if
(
ret
)
SetLastError
(
RtlNtStatusToDosError
(
ret
)
);
return
!
ret
;
}
...
...
@@ -1645,7 +244,8 @@ HW_end:
*/
HANDLE
WINAPI
GetProcessHeap
(
void
)
{
return
(
HANDLE
)
processHeap
;
HANDLE
*
pdb
=
(
HANDLE
*
)
NtCurrentTeb
()
->
process
;
return
pdb
[
0x18
/
sizeof
(
HANDLE
)];
/* get dword at offset 0x18 in pdb */
}
...
...
@@ -1654,20 +254,7 @@ HANDLE WINAPI GetProcessHeap(void)
*/
DWORD
WINAPI
GetProcessHeaps
(
DWORD
count
,
HANDLE
*
heaps
)
{
DWORD
total
;
HEAP
*
ptr
;
if
(
!
processHeap
)
return
0
;
/* should never happen */
total
=
1
;
/* main heap */
EnterCriticalSection
(
&
processHeap
->
critSection
);
for
(
ptr
=
firstHeap
;
ptr
;
ptr
=
ptr
->
next
)
total
++
;
if
(
total
<=
count
)
{
*
heaps
++
=
(
HANDLE
)
processHeap
;
for
(
ptr
=
firstHeap
;
ptr
;
ptr
=
ptr
->
next
)
*
heaps
++
=
(
HANDLE
)
ptr
;
}
LeaveCriticalSection
(
&
processHeap
->
critSection
);
return
total
;
return
RtlGetProcessHeaps
(
count
,
heaps
);
}
...
...
@@ -1675,35 +262,6 @@ DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
* 32-bit local heap functions (Win95; undocumented)
*/
#define HTABLE_SIZE 0x10000
#define HTABLE_PAGESIZE 0x1000
#define HTABLE_NPAGES (HTABLE_SIZE / HTABLE_PAGESIZE)
#include "pshpack1.h"
typedef
struct
_LOCAL32HEADER
{
WORD
freeListFirst
[
HTABLE_NPAGES
];
WORD
freeListSize
[
HTABLE_NPAGES
];
WORD
freeListLast
[
HTABLE_NPAGES
];
DWORD
selectorTableOffset
;
WORD
selectorTableSize
;
WORD
selectorDelta
;
DWORD
segment
;
LPBYTE
base
;
DWORD
limit
;
DWORD
flags
;
DWORD
magic
;
HANDLE
heap
;
}
LOCAL32HEADER
;
#include "poppack.h"
#define LOCAL32_MAGIC ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
/***********************************************************************
* K208 (KERNEL.208)
*/
...
...
@@ -1713,7 +271,7 @@ HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
DWORD
totSize
,
segSize
=
0
;
LPBYTE
base
;
LOCAL32HEADER
*
header
;
H
EAP
*
heap
;
H
ANDLE
heap
;
WORD
*
selectorTable
;
WORD
selectorEven
,
selectorOdd
;
int
i
,
nrBlocks
;
...
...
@@ -1748,8 +306,7 @@ HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
return
0
;
}
heap
=
(
HEAP
*
)(
base
+
segSize
+
HTABLE_SIZE
);
if
(
!
HEAP_InitSubHeap
(
heap
,
(
LPVOID
)
heap
,
0
,
0x10000
,
heapSize
)
)
if
(
!
(
heap
=
RtlCreateHeap
(
0
,
base
+
segSize
+
HTABLE_SIZE
,
heapSize
,
0x10000
,
NULL
,
NULL
)))
{
VirtualFree
(
base
,
0
,
MEM_RELEASE
);
return
0
;
...
...
@@ -1763,7 +320,7 @@ HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
header
->
limit
=
HTABLE_PAGESIZE
-
1
;
header
->
flags
=
0
;
header
->
magic
=
LOCAL32_MAGIC
;
header
->
heap
=
(
HANDLE
)
heap
;
header
->
heap
=
heap
;
header
->
freeListFirst
[
0
]
=
sizeof
(
LOCAL32HEADER
);
header
->
freeListLast
[
0
]
=
HTABLE_PAGESIZE
-
4
;
...
...
@@ -2146,8 +703,7 @@ static LOCAL32HEADER *Local32_GetHeap( HGLOBAL16 handle )
*/
BOOL16
WINAPI
Local32Info16
(
LOCAL32INFO
*
pLocal32Info
,
HGLOBAL16
handle
)
{
SUBHEAP
*
heapPtr
;
LPBYTE
ptr
;
PROCESS_HEAP_ENTRY
entry
;
int
i
;
LOCAL32HEADER
*
header
=
Local32_GetHeap
(
handle
);
...
...
@@ -2156,31 +712,24 @@ BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
if
(
!
pLocal32Info
||
pLocal32Info
->
dwSize
<
sizeof
(
LOCAL32INFO
)
)
return
FALSE
;
heapPtr
=
(
SUBHEAP
*
)
HEAP_GetPtr
(
header
->
heap
);
pLocal32Info
->
dwMemReserved
=
heapPtr
->
size
;
pLocal32Info
->
dwMemCommitted
=
heapPtr
->
commitSize
;
pLocal32Info
->
dwTotalFree
=
0L
;
pLocal32Info
->
dwLargestFreeBlock
=
0L
;
pLocal32Info
->
dwMemReserved
=
0
;
pLocal32Info
->
dwMemCommitted
=
0
;
pLocal32Info
->
dwTotalFree
=
0
;
pLocal32Info
->
dwLargestFreeBlock
=
0
;
/* Note: Local32 heaps always have only one subheap! */
ptr
=
(
LPBYTE
)
heapPtr
+
heapPtr
->
headerSize
;
while
(
ptr
<
(
LPBYTE
)
heapPtr
+
heapPtr
->
size
)
while
(
HeapWalk
(
header
->
heap
,
&
entry
))
{
if
(
*
(
DWORD
*
)
ptr
&
ARENA_FLAG_FREE
)
if
(
entry
.
wFlags
&
PROCESS_HEAP_REGION
)
{
ARENA_FREE
*
pArena
=
(
ARENA_FREE
*
)
ptr
;
DWORD
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
);
ptr
+=
sizeof
(
*
pArena
)
+
size
;
pLocal32Info
->
dwTotalFree
+=
size
;
if
(
size
>
pLocal32Info
->
dwLargestFreeBlock
)
pLocal32Info
->
dwLargestFreeBlock
=
size
;
pLocal32Info
->
dwMemReserved
+=
entry
.
u
.
Region
.
dwCommittedSize
+
entry
.
u
.
Region
.
dwUnCommittedSize
;
pLocal32Info
->
dwMemCommitted
=
entry
.
u
.
Region
.
dwCommittedSize
;
}
else
else
if
(
!
(
entry
.
wFlags
&
PROCESS_HEAP_ENTRY_BUSY
))
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DWORD
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
;
ptr
+=
sizeof
(
*
pArena
)
+
size
;
DWORD
size
=
entry
.
cbData
+
entry
.
cbOverhead
;
pLocal32Info
->
dwTotalFree
+=
size
;
if
(
size
>
pLocal32Info
->
dwLargestFreeBlock
)
pLocal32Info
->
dwLargestFreeBlock
=
size
;
}
}
...
...
memory/selector.c
View file @
b0f58617
...
...
@@ -518,6 +518,84 @@ DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
*
*/
struct
mapls_entry
{
struct
mapls_entry
*
next
;
void
*
addr
;
/* linear address */
int
count
;
/* ref count */
WORD
sel
;
/* selector */
};
static
struct
mapls_entry
*
first_entry
;
/***********************************************************************
* MapLS (KERNEL32.@)
* MapLS (KERNEL.358)
*
* Maps linear pointer to segmented.
*/
SEGPTR
WINAPI
MapLS
(
LPCVOID
ptr
)
{
struct
mapls_entry
*
entry
,
*
free
=
NULL
;
void
*
base
;
SEGPTR
ret
=
0
;
if
(
!
HIWORD
(
ptr
))
return
(
SEGPTR
)
ptr
;
base
=
(
char
*
)
ptr
-
((
unsigned
int
)
ptr
&
0x7fff
);
HeapLock
(
GetProcessHeap
()
);
for
(
entry
=
first_entry
;
entry
;
entry
=
entry
->
next
)
{
if
(
entry
->
addr
==
base
)
break
;
if
(
!
entry
->
count
)
free
=
entry
;
}
if
(
!
entry
)
{
if
(
!
free
)
/* no free entry found, create a new one */
{
if
(
!
(
free
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
free
)
)))
goto
done
;
if
(
!
(
free
->
sel
=
SELECTOR_AllocBlock
(
base
,
0x10000
,
WINE_LDT_FLAGS_DATA
)))
{
HeapFree
(
GetProcessHeap
(),
0
,
free
);
goto
done
;
}
free
->
count
=
0
;
free
->
next
=
first_entry
;
first_entry
=
free
;
}
SetSelectorBase
(
free
->
sel
,
(
DWORD
)
base
);
free
->
addr
=
base
;
entry
=
free
;
}
entry
->
count
++
;
ret
=
MAKESEGPTR
(
entry
->
sel
,
(
char
*
)
ptr
-
(
char
*
)
entry
->
addr
);
done:
HeapUnlock
(
GetProcessHeap
()
);
return
ret
;
}
/***********************************************************************
* UnMapLS (KERNEL32.@)
* UnMapLS (KERNEL.359)
*
* Free mapped selector.
*/
void
WINAPI
UnMapLS
(
SEGPTR
sptr
)
{
struct
mapls_entry
*
entry
;
WORD
sel
=
SELECTOROF
(
sptr
);
if
(
sel
)
{
HeapLock
(
GetProcessHeap
()
);
for
(
entry
=
first_entry
;
entry
;
entry
=
entry
->
next
)
if
(
entry
->
sel
==
sel
)
break
;
if
(
entry
&&
entry
->
count
>
0
)
entry
->
count
--
;
HeapUnlock
(
GetProcessHeap
()
);
}
}
/***********************************************************************
* MapSL (KERNEL32.@)
* MapSL (KERNEL.357)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment