en:docs:win16:modules:local_heap

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:docs:win16:modules:local_heap [2026/02/26 01:30] prokusheven:docs:win16:modules:local_heap [2026/03/02 07:53] (current) prokushev
Line 6: Line 6:
 In 16-bit versions of Windows (1.x, 2.x, 3.x), each module (application or DLL) typically has its own data segment (DGROUP) limited to 64 KB. This segment contains the stack, the local heap, and the atom table. Local heap functions manage memory within this segment using near pointers (offsets). They are exported by the KERNEL module. Internally, the local heap is managed through a set of data structures that reside inside the segment itself. In 16-bit versions of Windows (1.x, 2.x, 3.x), each module (application or DLL) typically has its own data segment (DGROUP) limited to 64 KB. This segment contains the stack, the local heap, and the atom table. Local heap functions manage memory within this segment using near pointers (offsets). They are exported by the KERNEL module. Internally, the local heap is managed through a set of data structures that reside inside the segment itself.
  
-A key part of this management is the Instance Data (also called the NULL segment) located at the very beginning of DGROUP, which holds pointers to the heap, atom table, and stack information. The field at offset 6 (pLocalHeap) contains a near pointer to the HeapInfo structure that heads the local heap. This pointer is set by [[en:docs:win16:api:kernel:LocalInit]]() and must be validated by checking the signature word (li_sig) at offset 22h (KRNL286) or 28h (KRNL386) within the presumed heap.+A key part of this management is the Instance Data (also called the NULL segment) located at the very beginning of DGROUP, which holds pointers to the heap, atom table, and stack information. The field at offset 6 (pLocalHeap) contains a near pointer to the HeapInfo structure that heads the local heap. This pointer is set by [[en:docs:win16:api:kernel:LocalInit]] and must be validated by checking the signature word (li_sig) at offset 22h (KRNL286) or 28h (KRNL386) within the presumed heap.
  
 The local heap itself is organized as a series of arenas (headers) that precede each block. The two low bits of the la_prev field in an arena are used as flags: bit 0 indicates whether the block is in use (1) or free (0); bit 1 indicates whether the block is MOVEABLE (1) or FIXED (0). Free blocks are linked via la_free_prev and la_free_next. For MOVEABLE blocks, a separate handle table (pointed to by hi_htable in HeapInfo) stores the actual address, lock count, and flags; each handle is an offset into this table. The local heap itself is organized as a series of arenas (headers) that precede each block. The two low bits of the la_prev field in an arena are used as flags: bit 0 indicates whether the block is in use (1) or free (0); bit 1 indicates whether the block is MOVEABLE (1) or FIXED (0). Free blocks are linked via la_free_prev and la_free_next. For MOVEABLE blocks, a separate handle table (pointed to by hi_htable in HeapInfo) stores the actual address, lock count, and flags; each handle is an offset into this table.
Line 18: Line 18:
 ^ Offset ^ Type ^ Field ^ Description ^ ^ Offset ^ Type ^ Field ^ Description ^
 | 00h | WORD | wMustBeZero | Must be zero for the NULL segment structure to be considered present. | | 00h | WORD | wMustBeZero | Must be zero for the NULL segment structure to be considered present. |
-| 02h | DWORD | dwOldSSSP | When [[en:docs:win16:api:kernel:SwitchStackTo]]() is called, the current SS:SP is stored here. At other times, may contain the value 5 (number of reserved pointers). | +| 02h | DWORD | dwOldSSSP | When [[en:docs:win16:api:kernel:SwitchStackTo]] is called, the current SS:SP is stored here. At other times, may contain the value 5 (number of reserved pointers). | 
-| 06h | WORD | pLocalHeap | Near pointer to the Local Heap information structure (i.e., the HeapInfo structure). This field is set by [[en:docs:win16:api:kernel:LocalInit]]() and points to the beginning of the local heap management structures. If no local heap exists, this field may be stale (non-zero but invalid). Always verify the heap by checking the signature at offset 22h (KRNL286) or 28h (KRNL386) – see li_sig below. | +| 06h | WORD | pLocalHeap | Near pointer to the Local Heap information structure (i.e., the HeapInfo structure). This field is set by [[en:docs:win16:api:kernel:LocalInit]] and points to the beginning of the local heap management structures. If no local heap exists, this field may be stale (non-zero but invalid). Always verify the heap by checking the signature at offset 22h (KRNL286) or 28h (KRNL386) – see li_sig below. | 
-| 08h | WORD | pAtomTable | Near pointer to the atom table structure. Set by [[en:docs:win16:api:kernel:InitAtomTable]](). Zero until atoms are used. |+| 08h | WORD | pAtomTable | Near pointer to the atom table structure. Set by [[en:docs:win16:api:kernel:InitAtomTable]]. Zero until atoms are used. |
 | 0Ah | WORD | pStackTop | Near pointer to the end (top) of the stack. For DLLs, this is zero. | | 0Ah | WORD | pStackTop | Near pointer to the end (top) of the stack. For DLLs, this is zero. |
 | 0Ch | WORD | pStackMin | High‑water mark of stack usage. For DLLs, zero. | | 0Ch | WORD | pStackMin | High‑water mark of stack usage. For DLLs, zero. |
Line 28: Line 28:
  
   * The field at offset 6 (pLocalHeap) is the primary way to locate the local heap structures given only the DGROUP selector.   * The field at offset 6 (pLocalHeap) is the primary way to locate the local heap structures given only the DGROUP selector.
-  * When [[en:docs:win16:api:kernel:LocalInit]]() is called on a globally allocated block (non‑DGROUP), the WORD at offset 6 of that block is also set to point to the local heap information structure for that block. +  * When [[en:docs:win16:api:kernel:LocalInit]] is called on a globally allocated block (non‑DGROUP), the WORD at offset 6 of that block is also set to point to the local heap information structure for that block. 
-  * Similarly, if [[en:docs:win16:api:kernel:InitAtomTable]]() is called on a global block, offset 8 points to the atom table, and offset 6 will point to the associated local heap (since atoms are stored in the local heap).+  * Similarly, if [[en:docs:win16:api:kernel:InitAtomTable]] is called on a global block, offset 8 points to the atom table, and offset 6 will point to the associated local heap (since atoms are stored in the local heap).
  
 ==== HeapInfo and LocalInfo ==== ==== HeapInfo and LocalInfo ====
Line 35: Line 35:
 Every local heap begins with an instance of the HeapInfo structure, which is identical to the one used by the global heap and is defined in WINKERN.INC. Its location is given by the pLocalHeap field at offset 6 of the Instance Data. Immediately following the HeapInfo structure are additional fields that, together with HeapInfo, form the LocalInfo structure. Every local heap begins with an instance of the HeapInfo structure, which is identical to the one used by the global heap and is defined in WINKERN.INC. Its location is given by the pLocalHeap field at offset 6 of the Instance Data. Immediately following the HeapInfo structure are additional fields that, together with HeapInfo, form the LocalInfo structure.
  
-===== HeapInfo Structure (386) =====+===== HeapInfo Structure (KRNL386) =====
  
 Under KRNL386, the HeapInfo structure occupies **1Eh** bytes and has the following format (according to "Windows Internals" documentation, Table 2-2): Under KRNL386, the HeapInfo structure occupies **1Eh** bytes and has the following format (according to "Windows Internals" documentation, Table 2-2):
Line 43: Line 43:
 | 02h | WORD | hi_freeze | If this is nonzero, KERNEL should not compact the heap. For the global heap, this value appears to be set only while inside the INT 24h handler. The local heap is frozen during [[en:docs:win16:api:kernel:LocalAlloc]] and [[en:docs:win16:api:kernel:LocalRealloc]]. [[en:docs:win16:api:kernel:LocalFreeze]] and [[en:docs:win16:api:kernel:LocalMelt]] also changes this field. | | 02h | WORD | hi_freeze | If this is nonzero, KERNEL should not compact the heap. For the global heap, this value appears to be set only while inside the INT 24h handler. The local heap is frozen during [[en:docs:win16:api:kernel:LocalAlloc]] and [[en:docs:win16:api:kernel:LocalRealloc]]. [[en:docs:win16:api:kernel:LocalFreeze]] and [[en:docs:win16:api:kernel:LocalMelt]] also changes this field. |
 | 04h | WORD | hi_count | The total number of blocks in the heap. | | 04h | WORD | hi_count | The total number of blocks in the heap. |
-| 06h | DWORD | hi_first | A far pointer to the arena header for the first block in the heap. The first block is always a sentinel and points to itself. | +| 06h | DWORD | hi_first | A far(?) pointer to the arena header for the first block in the heap. The first block is always a sentinel and points to itself. | 
-| 0Ah | DWORD | hi_last | A far pointer to the arena header for the last block in the heap. The last block is always a sentinel and points to itself. |+| 0Ah | DWORD | hi_last | A far(?) pointer to the arena header for the last block in the heap. The last block is always a sentinel and points to itself. |
 | 0Eh | BYTE | hi_ncompact | The number of compactions that have been performed on the heap to try and free up memory for a particular allocation. Some code appears to use this field as a count, while other code seems to use it as bitfields. | | 0Eh | BYTE | hi_ncompact | The number of compactions that have been performed on the heap to try and free up memory for a particular allocation. Some code appears to use this field as a count, while other code seems to use it as bitfields. |
 | 0Fh | BYTE | hi_dislevel | According to WINKERN.INC, it is the current discard level. Both the local and global heaps use it. The global heap treats the value as a bitfield, using it with flags such as GA_NODISCARD. | | 0Fh | BYTE | hi_dislevel | According to WINKERN.INC, it is the current discard level. Both the local and global heaps use it. The global heap treats the value as a bitfield, using it with flags such as GA_NODISCARD. |
Line 54: Line 54:
 | 1Ch | WORD | hi_pstats | A near pointer to a LocalStats structure which the local heap uses in the debug KERNEL. As the local heap does various things, such as search for free blocks, it increments fields in the structure. The structure is defined in WINKERN.INC. | | 1Ch | WORD | hi_pstats | A near pointer to a LocalStats structure which the local heap uses in the debug KERNEL. As the local heap does various things, such as search for free blocks, it increments fields in the structure. The structure is defined in WINKERN.INC. |
  
-===== HeapInfo Structure (286) =====+===== HeapInfo Structure (KRNL286) =====
 Under KRNL286, the HeapInfo structure occupies 18h bytes. The layout is as follows: Under KRNL286, the HeapInfo structure occupies 18h bytes. The layout is as follows: