Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / KernelLand / Kernel / heap.c
old mode 100644 (file)
new mode 100755 (executable)
index ba2957b..ba4c9ad
@@ -9,10 +9,12 @@
 #include <mm_virt.h>
 #include <heap_int.h>
 #include <limits.h>
+#include <debug_hooks.h>
 
 #define WARNINGS       1       // Warn and dump on heap errors
 #define        DEBUG_TRACE     0       // Enable tracing of allocations
 #define        VERBOSE_DUMP    0       // Set to 1 to enable a verbose dump when heap errors are encountered
+#define VALIDATE_ON_ALLOC      1       // Set to 1 to enable validation of the heap on all malloc() calls
 
 // === CONSTANTS ===
 #define        HEAP_INIT_SIZE  0x8000  // 32 KiB
 void   Heap_Install(void);
 void   *Heap_Extend(size_t Bytes);
 void   *Heap_Merge(tHeapHead *Head);
+static const size_t    Heap_int_GetBlockSize(size_t AllocSize);
 //void *Heap_Allocate(const char *File, int Line, size_t Bytes);
 //void *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
 //void *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
 //void Heap_Deallocate(const char *File, int Line, void *Ptr);
-void   Heap_Dump(int bVerbose);
-void   Heap_Stats(void);
+ int   Heap_int_ApplyWatchpont(void *Addr, bool Enabled);
+void   Heap_int_WatchBlock(tHeapHead *Head, bool Enabled);
+//void Heap_Dump(void);
+void   Heap_ValidateDump(int bVerbose);
+//void Heap_Stats(void);
 
 // === GLOBALS ===
 tMutex glHeap;
@@ -68,8 +74,7 @@ static inline tHeapFoot *Heap_PrevFoot(tHeapHead *Head) {
  */
 void *Heap_Extend(size_t Bytes)
 {
-
-       Debug("Heap_Extend(0x%x)", Bytes);
+       //Debug("Heap_Extend(0x%x)", Bytes);
        
        // Bounds Check
        if( gHeapEnd == (tHeapHead*)MM_KHEAP_MAX ) {
@@ -88,17 +93,17 @@ void *Heap_Extend(size_t Bytes)
        if( new_end > (tHeapHead*)MM_KHEAP_MAX )
        {
                Log_Error("Heap", "Heap limit exceeded (%p)", (void*)new_end);
-               // TODO: Clip allocation to avaliable space, and have caller check returned block
+               // TODO: Clip allocation to available space, and have caller check returned block
                return NULL;
        }
        
        // Heap expands in pages
        for( Uint i = 0; i < pages; i ++ )
        {
-               if( !MM_Allocate( (tVAddr)gHeapEnd+(i<<12) ) )
+               if( !MM_Allocate( (tPage*)gHeapEnd + i ) )
                {
                        Warning("OOM - Heap_Extend (%i bytes)");
-                       Heap_Dump(1);
+                       Heap_Dump();
                        return NULL;
                }
        }
@@ -118,24 +123,19 @@ void *Heap_Extend(size_t Bytes)
 }
 
 /**
- * \brief Merges two ajacent heap blocks
+ * \brief Merges two adjacent heap blocks
  */
 void *Heap_Merge(tHeapHead *Head)
 {
-       tHeapFoot       *foot;
-       tHeapFoot       *thisFoot;
-       tHeapHead       *head;
-       
        //Log("Heap_Merge: (Head=%p)", Head);
+       tHeapFoot *thisFoot = Heap_ThisFoot(Head);
        
-       thisFoot = Heap_ThisFoot(Head);
-       if( (void*)thisFoot > (void*)gHeapEnd )
-               return NULL;
+       ASSERT( Heap_NextHead(Head) <= gHeapEnd );
        
        // Merge Left (Down)
-       foot = Heap_PrevFoot(Head);
-       if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
-       && foot->Head->Magic == MAGIC_FREE) {
+       tHeapFoot *foot = Heap_PrevFoot(Head);
+       if( Head > gHeapStart && foot->Head->Magic == MAGIC_FREE)
+       {
                foot->Head->Size += Head->Size; // Increase size
                thisFoot->Head = foot->Head;    // Change backlink
                Head->Magic = 0;        // Clear old head
@@ -146,22 +146,34 @@ void *Heap_Merge(tHeapHead *Head)
        }
        
        // Merge Right (Upwards)
-       head = Heap_NextHead(Head);
-       if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
+       tHeapHead *nexthead = Heap_NextHead(Head);
+       if(nexthead < gHeapEnd && nexthead->Magic == MAGIC_FREE)
        {
-               Head->Size += head->Size;
+               Head->Size += nexthead->Size;
                foot = Heap_ThisFoot(Head);
                foot->Head = Head;      // Update Backlink
                thisFoot->Head = NULL;  // Clear old footer
                thisFoot->Magic = 0;
-               head->Size = 0;         // Clear old header
-               head->Magic = 0;
+               nexthead->Size = 0;             // Clear old header
+               nexthead->Magic = 0;
        }
        
        // Return new address
        return Head;
 }
 
+static const size_t Heap_int_GetBlockSize(size_t AllocSize)
+{
+       size_t Bytes;
+       #if POW2_SIZES
+       Bytes = AllocSize + sizeof(tHeapHead) + sizeof(tHeapFoot);
+       Bytes = 1UUL << LOG2(Bytes);
+       #else
+       Bytes = (AllocSize + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1);
+       #endif
+       return Bytes;
+}
+
 /**
  * \param File Allocating source file
  * \param Line Source line
@@ -179,14 +191,13 @@ void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
                return NULL;    // TODO: Return a known un-mapped range.
 //             return INVLPTR;
        }
+
+       #if VALIDATE_ON_ALLOC
+       Heap_Validate();
+       #endif
        
        // Get required size
-       #if POW2_SIZES
-       Bytes = __Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot);
-       Bytes = 1UUL << LOG2(__Bytes);
-       #else
-       Bytes = (__Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1);
-       #endif
+       Bytes = Heap_int_GetBlockSize(__Bytes);
        
        // Lock Heap
        Mutex_Acquire(&glHeap);
@@ -205,24 +216,28 @@ void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
                        Log_Warning("Heap", "Size of heap address %p is invalid"
                                " - not aligned (0x%x) [at paddr 0x%x]",
                                head, head->Size, MM_GetPhysAddr(&head->Size));
-                       Heap_Dump(VERBOSE_DUMP);
+                       Heap_ValidateDump(VERBOSE_DUMP);
                        #endif
                        return NULL;
                }
                if( head->Size < MIN_SIZE ) {
                        Mutex_Release(&glHeap);
+                       #if WARNINGS
                        Log_Warning("Heap", "Size of heap address %p is invalid"
                                " - Too small (0x%x) [at paddr 0x%x]",
                                head, head->Size, MM_GetPhysAddr(&head->Size));
-                       Heap_Dump(VERBOSE_DUMP);
+                       Heap_ValidateDump(VERBOSE_DUMP);
+                       #endif
                        return NULL;
                }
                if( head->Size > (2<<30) ) {
                        Mutex_Release(&glHeap);
+                       #if WARNINGS
                        Log_Warning("Heap", "Size of heap address %p is invalid"
                                " - Over 2GiB (0x%x) [at paddr 0x%x]",
                                head, head->Size, MM_GetPhysAddr(&head->Size));
-                       Heap_Dump(VERBOSE_DUMP);
+                       Heap_ValidateDump(VERBOSE_DUMP);
+                       #endif
                        return NULL;
                }
                
@@ -234,7 +249,7 @@ void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
                        #if WARNINGS
                        Log_Warning("Heap", "Magic of heap address %p is invalid (%p = 0x%x)",
                                head, &head->Magic, head->Magic);
-                       Heap_Dump(VERBOSE_DUMP);
+                       Heap_ValidateDump(VERBOSE_DUMP);
                        #endif
                        return NULL;
                }
@@ -338,6 +353,8 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr)
        // INVLPTR is returned from Heap_Allocate when the allocation
        // size is zero.
        if( Ptr == INVLPTR )    return;
+       // free(NULL) is a no-op
+       if( Ptr == NULL )       return;
        
        // Alignment Check
        if( (tVAddr)Ptr % sizeof(void*) != 0 ) {
@@ -354,11 +371,12 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr)
        }
        
        // Check memory block - Header
-       tHeapHead *head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
+       tHeapHead *head = (tHeapHead*)Ptr - 1;
        if(head->Magic == MAGIC_FREE) {
                Log_Warning("Heap", "free - Passed a freed block (%p) by %s:%i (was freed by %s:%i)",
                        head, File, Line,
                        head->File, head->Line);
+               Proc_PrintBacktrace();
                return;
        }
        if(head->Magic != MAGIC_USED) {
@@ -388,7 +406,9 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr)
        
        // Lock
        Mutex_Acquire( &glHeap );
-       
+
+       Heap_int_WatchBlock(head, false);
+
        // Mark as free
        head->Magic = MAGIC_FREE;
        head->File = File;
@@ -410,16 +430,36 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr)
  */
 void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
 {
-       tHeapHead       *head = (void*)( (Uint)__ptr-sizeof(tHeapHead) );
+       tHeapHead       *head = (tHeapHead*)__ptr - 1;
        tHeapHead       *nextHead;
        tHeapFoot       *foot;
-       Uint    newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+MIN_SIZE-1)&~(MIN_SIZE-1);
+       Uint    newSize = Heap_int_GetBlockSize(__size);
        
        // Check for reallocating NULL
-       if(__ptr == NULL)       return Heap_Allocate(File, Line, __size);
+       if(__ptr == NULL)
+               return Heap_Allocate(File, Line, __size);
+       
+       if( !Heap_IsHeapAddr(__ptr)) {
+               Log_Error("Heap", "%s:%i passed non-heap address %p when reallocating to %zi",
+                       File, Line, __ptr, __size);
+               return NULL;
+       }
        
        // Check if resize is needed
-       if(newSize <= head->Size)       return __ptr;
+       // TODO: Reduce size of block if needed
+       if(newSize <= head->Size) {
+               #if DEBUG_TRACE
+               Log_Debug("Heap", "realloc maintain %p (0x%x >= 0x%x), returning to %s:%i",
+                       head->Data, head->Size, newSize, File, Line);
+               #endif
+               return __ptr;
+       }
+
+       #if VALIDATE_ON_ALLOC
+       Heap_Validate();
+       #endif
+       
+       Heap_int_WatchBlock(head, false);
        
        // Check if next block is free
        nextHead = Heap_NextHead(head);
@@ -427,6 +467,10 @@ void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
        // Extend into next block
        if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
        {
+               #if DEBUG_TRACE
+               Log_Debug("Heap", "realloc expand %p (0x%x to 0x%x), returning to %s:%i",
+                       head->Data, head->Size, newSize, File, Line);
+               #endif
                Uint    size = nextHead->Size + head->Size;
                foot = Heap_ThisFoot(nextHead);
                // Exact Fit
@@ -455,7 +499,7 @@ void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
                nextHead->Size = size - newSize;
                nextHead->Magic = MAGIC_FREE;
                // - Update old footer
-               foot->Head = nextHead;
+               Heap_ThisFoot(nextHead)->Head = nextHead;
                return __ptr;
        }
        
@@ -472,6 +516,11 @@ void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
                        Warning("[Heap   ] TODO: Space efficient realloc when new size is smaller");
                }
                
+               #if DEBUG_TRACE
+               Log_Debug("Heap", "realloc expand down %p (0x%x to 0x%x), returning to %s:%i",
+                       head->Data, head->Size, newSize, File, Line);
+               #endif
+               
                // Exact fit
                Uint    oldDataSize;
                // Set 1st (new/lower) header
@@ -502,6 +551,8 @@ void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
        nextHead->Line = Line;
        nextHead->ValidSize = __size;
        
+       ASSERTC(head->Size, <, nextHead->Size);
+       ASSERTC(__ptr, ==, head->Data);
        memcpy(
                nextHead->Data,
                __ptr,
@@ -509,7 +560,8 @@ void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
                );
        
        free(__ptr);
-       
+       Heap_Validate();
+
        return nextHead->Data;
 }
 
@@ -548,16 +600,95 @@ int Heap_IsHeapAddr(void *Ptr)
        return 1;
 }
 
+int Heap_int_ApplyWatchpont(void *Word, bool enabled)
+{
+       #if ARCHDIR_IS_x86
+       static void     *active_wps[4];
+       unsigned int    dr;
+       for( dr = 2; dr < 4; dr ++ )
+       {
+               if( (enabled && active_wps[dr] == NULL) || active_wps[dr] == Word)
+                       break;
+       }
+       if(dr == 4) {
+               return 1;
+       }
+       if( enabled )
+       {
+               active_wps[dr] = Word;
+               switch(dr)
+               {
+               //case 0:       ASM("mov %0, %%dr0" : : "r" (Word));    break;
+               //case 1:       ASM("mov %0, %%dr1" : : "r" (Word));    break;
+               case 2: ASM("mov %0, %%dr2" : : "r" (Word));    break;
+               case 3: ASM("mov %0, %%dr3" : : "r" (Word));    break;
+               default:        ASSERTC(dr,<,4);        return 1;
+               }
+       }
+       else
+       {
+               active_wps[dr] = NULL;
+       }
+       Uint32  dr7flag;
+       ASM("MOV %%dr7, %0" : "=r" (dr7flag));
+       dr7flag &= ~(0x2 << (dr*2));
+       dr7flag &= ~(0xF000 << (dr*4));
+       if( enabled ) {
+               dr7flag |= 0x2 << (dr*2);
+               dr7flag |= 0xD000 << (dr*4);    // 4 bytes, write
+               Debug("Heap_int_ApplyWatchpont: Watchpoint #%i %p ENABLED", dr, Word);
+       }
+       else {
+               Debug("Heap_int_ApplyWatchpont: Watchpoint #%i %p disabled", dr, Word);
+       }
+       ASM("MOV %0, %%dr7" : : "r" (dr7flag));
+       return 0;
+       #else
+       return 1;
+       #endif
+}
+
+void Heap_int_WatchBlock(tHeapHead *Head, bool Enabled)
+{
+       int rv;
+       rv = Heap_int_ApplyWatchpont( &Head->Size, Enabled );
+       //rv = Heap_int_ApplyWatchpont( &Head->Magic, Enabled );
+       rv = rv + Heap_int_ApplyWatchpont( &Heap_ThisFoot(Head)->Head, Enabled );
+       if(rv && Enabled) {
+               Warning("Can't apply watch on %p", Head);
+       }
+}
+
+int Heap_WatchBlock(void *Ptr)
+{
+       //Heap_int_ApplyWatchpont();
+       tHeapHead       *head;
+       if((Uint)Ptr < (Uint)gHeapStart)        return 0;
+       if((Uint)Ptr > (Uint)gHeapEnd)  return 0;
+       if((Uint)Ptr & (sizeof(Uint)-1))        return 0;
+       
+       head = (tHeapHead*)Ptr - 1;
+       
+       Heap_int_WatchBlock( head, true );
+       
+       return 0;
+}
+
 /**
  */
 void Heap_Validate(void)
 {
        // Call dump non-verbosely.
        // - If a heap error is detected, it'll print
-       Heap_Dump(0);
+       Heap_ValidateDump(0);
+}
+
+void Heap_Dump(void)
+{
+       Heap_ValidateDump(1);
 }
 
-void Heap_Dump(int bVerbose)
+void Heap_ValidateDump(int bVerbose)
 {
        tHeapHead       *head, *badHead;
        tHeapFoot       *foot = NULL;
@@ -627,7 +758,7 @@ void Heap_Dump(int bVerbose)
                in_heap_dump = 0;
                return ;
        }
-
+       
        // If not verbose, we need to dump the failing block
        if( !bVerbose )
        {
@@ -641,8 +772,7 @@ void Heap_Dump(int bVerbose)
                }
                Log_Log("Heap", "");
        }
-       
-       
+               
        badHead = head;
        
        // Work backwards
@@ -691,7 +821,7 @@ void Heap_Dump(int bVerbose)
                Log_Debug("Heap", "head=%p", head);
        }
        
-       Panic("Heap_Dump - Heap is corrupted, kernel panic!");
+       Panic("Heap_Dump - Heap is corrupted, kernel panic! (%p)", badHead);
 }
 
 void Heap_Stats(void)

UCC git Repository :: git.ucc.asn.au