; *Not* the original file, but an edit to turn it into an includable slice. ; The following things were removed: ; * RULES.ASI to eliminate redundancy ; * any extern data declarations ; * the 'CODE' segment declaration (for obvious reasons) ; * the ARG directives (they don't compile correctly for some reason) ;[]-----------------------------------------------------------------[] ;| FEAPCHK.ASM | ;[]-----------------------------------------------------------------[] ; ; C/C++ Run Time Library - Version 5.0 ; ; Copyright (c) 1987, 1992 by Borland International ; All Rights Reserved. ; INCLUDE _HEAP.INC IF LPROG EXTRADISP equ 2 ; Allow for FAR returns when getting parms DIST equ FAR ELSE EXTRADISP equ 0 DIST equ NEAR ENDIF ;----------------------------------------------------------------------- ; Memory Block Header (far heap) ;----------------------------------------------------------------------- ; Each block in the heap, whether allocated or free, has a header. ; For an allocated block, only the first two fields of the header are ; used. For a free block all ten bytes are used. Blocks are aligned on ; paragraph boundaries, thus the smallest possible block sixteen bytes. ; ; Field Description ; --------- ---------------------------------------------------------- ; size total size, in paragraphs, of this block ; prev_real segment of the physically previous block in the heap ; prev_real is 0 this block is free, get the prev_real from prev_real2 ; prev_free segment of the logically previous free block ; next_free segment of the logically next free block ; prev_real2 segment of the physically previous block in the heap ; free_space first byte of free space available ; ; A doubly-linked queue is maintained of the free blocks and it is important ; to know that ordering of the blocks in this queue is logical rather than ; physical. If there is only one free block on the heap prev_free and ; next_free point to itself. ;----------------------------------------------------------------------- bsize EQU 0 prev_real EQU 2 prev_free EQU 4 next_free EQU 6 prev_real2 EQU 8 free_space EQU 10 ;----------------------------------------------------------------------- ; heapinfo structure (far heap) ;----------------------------------------------------------------------- ; Used by the heapwalk function. ; heapwalk accepts a pointer to a struct of this type. ; On entry, the pointer field contains the address of the previous ; memory block in the heap (NULL for the first call). The next block ; in the heap is then found and its address is stored in the structure ; along with its size, in bytes, and a 'used' flag. ;----------------------------------------------------------------------- HeapInfo STRUC hi_ptr dd ? hi_size dd ? hi_inuse dw ? ENDS UsedHeaderSize EQU 4 FreeHeaderSize EQU 10 ;----------------------------------------------------------------------------- ; C callable function which checks and verifies the heap. ; Walk through the physical heap and free block queue checking for ; bad links, adjacent free blocks, and sum the free block sizes both ; ways. If the physical free block sum does not equal the free-block ; queue sum, there is an error. ; ; Args: void ; Returns: _HEAPEMPTY, _HEAPOK, or _HEAPCORRUPT in ax ;----------------------------------------------------------------------------- IF LDATA PUBLIC _heapcheck _heapcheck LABEL DIST ENDIF PUBLIC _farheapcheck _farheapcheck PROC DIST push si push di push bp push ds mov ax,cs:[___first] or ax,ax jnz @@HeapNotEmpty jmp @@EmptyHeap @@HeapNotEmpty: xor bx,bx push bx push bx call __sbrk ;retrieve the break level add sp,4 or ax,ax jz @@GoodOffset jmp @@HeapCorrupt @@GoodOffset: mov bx,cs:[___last] mov ds,bx add bx,ds:[bsize] cmp bx,dx je @@CheckHeap jmp @@HeapCorrupt @@CheckHeap: mov ax,cs:[___first] xor cx,cx ;cx = sum of physical free mov dx,cx ;dx = sum of logical free mov ds,ax ;ds = first block in the heap add ax,WORD PTR ds:[bsize] mov es,ax ;ax,es = next block in the heap @@SearchPhysicalLinks: cmp WORD PTR ds:[prev_real],0 ;is this block used? jne @@CheckPhysicalLinks ;yep, skip this section add cx,ds:[bsize] mov si,ds ;si = ds cmp si,cs:[___last] ;end-of-heap? je @@QueueCheck cmp WORD PTR es:[prev_real],0 ;is the next block free? jnz @@CheckPhysicalLinks jmp @@HeapCorrupt @@CheckPhysicalLinks: mov si,ds ;si = ds mov di,es ;di = es cmp si,cs:[___last] ;end-of-heap? je @@QueueCheck cmp si,di ;check those links! je @@HeapCorrupt cmp WORD PTR ds:[bsize],0 je @@HeapCorrupt cmp di,cs:[___first] jbe @@HeapCorrupt cmp di,cs:[___last] ja @@HeapCorrupt cmp WORD PTR es:[prev_real],0 je @@NextBlockIsFree @@NextBlockIsUsed: cmp es:[prev_real],si jmp @@CheckPrevReal @@NextBlockIsFree: cmp es:[prev_real2],si @@CheckPrevReal: jne @@HeapCorrupt mov ds,di ;ds = es add di,WORD PTR ds:[bsize] mov es,di ;es = next block in the heap jmp SHORT @@SearchPhysicalLinks @@QueueCheck: mov ax,cs:[___rover] ;ax = rover pointer or ax,ax jz @@EvaluateResults mov ds,ax ;ds = free block mov si,ax ;si = ds @@QueueLoop: cmp WORD PTR ds:[prev_real],0 ;this block should be free jne @@HeapCorrupt cmp si,cs:[___first] jb @@HeapCorrupt cmp si,cs:[___last] jae @@HeapCorrupt add dx,ds:[bsize] ;dx += size of this block mov es,ds:[next_free] ;es = next free block mov di,es ;di = es cmp di,ax ;done? je @@EvaluateResults cmp si,di ;check those links? je @@HeapCorrupt cmp es:[prev_free],si jne @@HeapCorrupt mov si,es ;ds = es mov ds,si jmp SHORT @@QueueLoop @@HeapCorrupt: mov ax,_HEAPCORRUPT jmp SHORT @@AllDone @@EmptyHeap: mov ax,_HEAPEMPTY jmp SHORT @@AllDone @@EvaluateResults: cmp cx,dx jne @@HeapCorrupt @@HeapOK: mov ax,_HEAPOK @@AllDone: pop ds pop bp pop di pop si ret ENDP ;----------------------------------------------------------------------------- ; C callable function which checks and verifies a node on the heap. ;----------------------------------------------------------------------------- ; Args: node to check (stack) ; Returns: _HEAPCORRUPT, _BADNODE, _FREEENTRY, or _USEDENTRY in ax ;----------------------------------------------------------------------------- IF LDATA PUBLIC _heapchecknode _heapchecknode LABEL DIST ENDIF PUBLIC _farheapchecknode _farheapchecknode PROC DIST push bp mov bp,sp push si push di push ds call _farheapcheck ;make sure heap is OK first cmp ax, _HEAPOK jne @@AllDone mov ax,[bp+8] ;ax = segment to search for mov si,cs:[___first] ;si = first block mov di,cs:[___last] ;di = last block mov bx,si ;bx = first block @@SearchPhysicalLinks: mov ds,bx cmp bx,ax ;is this it? je @@Found cmp WORD PTR ds:[prev_real],0 je @@BlockIsFree @@BlockIsUsed: cmp ds:[prev_real],si jb @@HeapCorrupt jmp SHORT @@Around @@BlockIsFree: cmp ds:[prev_real2],si jb @@HeapCorrupt @@Around: cmp bx,di je @@NotFound ja @@HeapCorrupt mov cx,bx add bx,ds:[bsize] cmp bx,cx jne @@SearchPhysicalLinks @@HeapCorrupt: mov ax,_HEAPCORRUPT jmp SHORT @@AllDone @@EmptyHeap: mov ax,_HEAPEMPTY jmp SHORT @@AllDone @@NotFound: mov ax,_BADNODE jmp SHORT @@AllDone @@Found: cmp WORD PTR ds:[prev_real],0 jnz @@UsedEntry @@FreeEntry: mov ax,_FREEENTRY jmp SHORT @@AllDone @@UsedEntry: mov ax,_USEDENTRY @@AllDone: pop ds pop di pop si pop bp ret ENDP ;----------------------------------------------------------------------------- ; C callable function which fills the free areas with a given value ;----------------------------------------------------------------------------- ; Args: unsigned int, fill value (stack) ; Returns: _HEAPEMPTY, _HEAPOK, or _HEAPCORRUPT in ax ;----------------------------------------------------------------------------- IF LDATA PUBLIC _heapfillfree _heapfillfree LABEL DIST ENDIF PUBLIC _farheapfillfree _farheapfillfree PROC DIST push bp mov bp,sp push si push di call _farheapcheck ;make sure heap is OK first cmp ax, _HEAPOK jne @@AllDone mov bx,cs:___rover ;bx = rover pointer or bx,bx jz @@HeapOK cld mov ax,[bp+6] ;ax = fill value @@QueueLoop: mov es,bx ;es,bx = free block mov dx,es:[bsize] ;dx = size of block (in para) mov si,es:[next_free] ;si = next free block mov di,free_space mov cx,8 - (free_space/2) @@FillHerUp: rep stosw xor di,di mov cx,8 inc bx mov es,bx dec dx jnz @@FillHerUp @@NextBlock: cmp si,cs:[___rover] je @@HeapOK or si,si jz @@HeapCorrupt mov bx,si jmp SHORT @@QueueLoop @@HeapCorrupt: mov ax,_HEAPCORRUPT jmp SHORT @@AllDone @@EmptyHeap: mov ax,_HEAPEMPTY jmp SHORT @@AllDone @@HeapOK: mov ax,_HEAPOK @@AllDone: pop di pop si pop bp ret ENDP ;----------------------------------------------------------------------------- ; C callable function which checks the free areas of the heap for a given value ;----------------------------------------------------------------------------- ; Args: unsigned int, fill value (stack) ; Returns: _HEAPOK, _HEAPEMPTY, _BADVALUE, or _HEAPCORRUPT in ax ;----------------------------------------------------------------------------- IF LDATA PUBLIC _heapcheckfree _heapcheckfree LABEL DIST ENDIF PUBLIC _farheapcheckfree _farheapcheckfree PROC DIST push bp mov bp,sp push si push di call _farheapcheck ;make sure heap is OK first cmp ax, _HEAPOK jne @@AllDone mov bx,cs:___rover ;bx = rover pointer or bx,bx jz @@HeapOK mov ax,[bp+6] ;ax = fill value cld @@QueueLoop: mov es,bx ;es,bx = free block mov dx,es:[bsize] ;dx = size of block (in para) mov si,es:[next_free] ;si = next free block mov di,free_space mov cx,8 - (free_space/2) @@CheckHerOut: repe scasw jnz @@BadValue xor di,di mov cx,8 inc bx mov es,bx dec dx jnz @@CheckHerOut @@NextBlock: cmp si,cs:[___rover] je @@HeapOK or si,si jz @@HeapCorrupt mov bx,si jmp SHORT @@QueueLoop @@BadValue: mov ax,_BADVALUE jmp SHORT @@AllDone @@HeapCorrupt: mov ax,_HEAPCORRUPT jmp SHORT @@AllDone @@EmptyHeap: mov ax,_HEAPEMPTY jmp SHORT @@AllDone @@HeapOK: mov ax,_HEAPOK @@AllDone: pop di pop si pop bp ret ENDP ;----------------------------------------------------------------------------- ; C callable function to walk through the heap node by node ;----------------------------------------------------------------------------- ; Args: pointer to a heapinfo structure (stack) ; Returns: _HEAPOK, _HEAPEMPTY, _HEAPEND in ax ;----------------------------------------------------------------------------- IF LDATA PUBLIC _heapwalk _heapwalk LABEL DIST ENDIF PUBLIC _farheapwalk _farheapwalk PROC DIST push bp mov bp,sp push si push di mov di,[bp+6] ;di = offset of struct IF LDATA push ds mov bx,[bp+8] ;bx = segment of struct cmp di,0FFF0h ;psuedo-normalize it jb @@Normalized inc bx sub di,16d @@Normalized: mov ds,bx ;ds:di = struct ENDIF mov bx,WORD PTR [di+hi_ptr+2] ;bx = previous block or bx,bx jz @@FirstBlock cmp bx,cs:[___last] ;last block? je @@HeapEnd or bx,bx ;first? jne @@InnerBlock @@FirstBlock: mov bx,cs:[___first] or bx,bx jz @@HeapEmpty mov es,bx ;es = first block jmp SHORT @@SaveInfo @@InnerBlock: mov es,bx ;es = block add bx,es:[bsize] ;bx = next block mov es,bx ;es = next block @@SaveInfo: mov WORD PTR ds:[di+hi_ptr+2],es ;save address mov WORD PTR ds:[di+hi_ptr],UsedHeaderSize mov ax,WORD PTR es:[bsize] ;multiply size * 16 mov bx,16d mul bx mov WORD PTR ds:[di+hi_size],ax ;save it mov WORD PTR ds:[di+hi_size+2],dx mov WORD PTR ds:[di+hi_inuse],0 ;clear in-use flag cmp WORD PTR es:[prev_real], 0 ;is it free? je @@HeapOK inc WORD PTR ds:[di+hi_inuse] ;set in-use flag @@HeapOK: mov ax,_HEAPOK jmp SHORT @@AllDone @@HeapEmpty: mov ax,_HEAPEMPTY jmp SHORT @@AllDone @@HeapEnd: mov ax,_HEAPEND @@AllDone: IF LDATA pop ds ENDIF pop di pop si pop bp ret ENDP