| //===- PoolAllocatorBitMask.cpp - Implementation of poolallocator runtime -===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is one possible implementation of the LLVM pool allocator runtime |
| // library. |
| // |
| // This uses the 'Ptr1' field to maintain a linked list of slabs that are either |
| // empty or are partially allocated from. The 'Ptr2' field of the PoolTy is |
| // used to track a linked list of slabs which are full, ie, all elements have |
| // been allocated from them. |
| // |
| //===----------------------------------------------------------------------===// |
| // NOTE: |
| // 1) Some of the bounds checking code may appear strange. The reason is that |
| // it is manually inlined to squeeze out some more performance. Please |
| // don't change it. |
| //===----------------------------------------------------------------------===// |
| |
| #include "PoolAllocator.h" |
| #include "PageManager.h" |
| #include "Report.h" |
| #include "adl_splay.h" |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <unistd.h> |
| #include <signal.h> |
| #include <ucontext.h> |
| #include <sys/mman.h> |
| //#include <sys/ucontext.h> |
| #define DEBUG(x) |
| |
| // global variable declarations |
| extern unsigned PPageSize; |
| static unsigned globalallocID = 0; |
| static unsigned globalfreeID = 0; |
| static void * globalTemp = 0; |
| static PoolTy dummyPool; |
| static unsigned dummyInitialized = 0; |
| unsigned poolmemusage = 0; |
| |
| // Invalid address range |
| #if !defined(__linux__) |
| unsigned InvalidUpper = 0x00000000; |
| unsigned InvalidLower = 0x00000003; |
| #endif |
| |
| // Splay tree of external objects |
| extern void * ExternalObjects; |
| |
| /* Set to 1 to log object registrations */ |
| static /*const*/ unsigned logregs = 0; |
| |
| // signal handler |
| static void bus_error_handler(int, siginfo_t *, void *); |
| |
| // creates a new PtrMetaData structure to record pointer information |
| static inline void updatePtrMetaData(PDebugMetaData, unsigned, void *); |
| static PDebugMetaData createPtrMetaData (unsigned, |
| unsigned, |
| void *, |
| void *, |
| void *); |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // PoolSlab implementation |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // PoolSlab Structure - Hold multiple objects of the current node type. |
| // Invariants: FirstUnused <= UsedEnd |
| // |
| struct PoolSlab { |
| PoolSlab **PrevPtr, *Next; |
| bool isSingleArray; // If this slab is used for exactly one array |
| unsigned allocated; // Number of bytes allocated |
| PoolSlab * Canonical; // For stack slabs, the canonical page |
| |
| private: |
| // FirstUnused - First empty node in slab |
| unsigned short FirstUnused; |
| |
| // UsedBegin - The first node in the slab that is used. |
| unsigned short UsedBegin; |
| |
| // UsedEnd - 1 past the last allocated node in slab. 0 if slab is empty |
| unsigned short UsedEnd; |
| |
| // NumNodesInSlab - This contains the number of nodes in this slab, which |
| // effects the size of the NodeFlags vector, and indicates the number of nodes |
| // which are in the slab. |
| unsigned int NumNodesInSlab; |
| |
| // Size of Slab - For single array slabs, specifies the size of the slab in |
| // bytes from beginning to end (including slab header). |
| // |
| public: |
| unsigned int SizeOfSlab; |
| |
| private: |
| // NodeFlagsVector - This array contains two bits for each node in this pool |
| // slab. The first (low address) bit indicates whether this node has been |
| // allocated, and the second (next higher) bit indicates whether this is the |
| // start of an allocation. |
| // |
| // This is a variable sized array, which has 2*NumNodesInSlab bits (rounded up |
| // to 4 bytes). |
| unsigned NodeFlagsVector[1]; |
| |
| bool isNodeAllocated(unsigned NodeNum) { |
| return NodeFlagsVector[NodeNum/16] & (1 << (NodeNum & 15)); |
| } |
| |
| void markNodeAllocated(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] |= 1 << (NodeNum & 15); |
| } |
| |
| void markNodeFree(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] &= ~(1 << (NodeNum & 15)); |
| } |
| |
| void setStartBit(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] |= 1 << ((NodeNum & 15)+16); |
| } |
| |
| bool isStartOfAllocation(unsigned NodeNum) { |
| return NodeFlagsVector[NodeNum/16] & (1 << ((NodeNum & 15)+16)); |
| } |
| |
| void clearStartBit(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] &= ~(1 << ((NodeNum & 15)+16)); |
| } |
| |
| void assertOkay (void) { |
| assert (FirstUnused <= UsedEnd); |
| assert ((UsedEnd == getSlabSize()) || (!isNodeAllocated(UsedEnd))); |
| assert ((FirstUnused == getSlabSize()) || (!isNodeAllocated(FirstUnused))); |
| } |
| public: |
| // create - Create a new (empty) slab and add it to the end of the Pools list. |
| static PoolSlab *create(PoolTy *Pool); |
| |
| // createSingleArray - Create a slab for a large singlearray with NumNodes |
| // entries in it, returning the pointer into the pool directly. |
| static void *createSingleArray(PoolTy *Pool, unsigned NumNodes); |
| |
| // getSlabSize - Return the number of nodes that each slab should contain. |
| static unsigned getSlabSize(PoolTy *Pool) { |
| // We need space for the header... |
| unsigned NumNodes = PageSize-sizeof(PoolSlab); |
| |
| // We need space for the NodeFlags... |
| // FIXME: |
| // We unconditionally round up a byte. We should only do that if |
| // necessary. |
| unsigned NodeFlagsBytes = (NumNodes/Pool->NodeSize * 2 / 8) + 1; |
| NumNodes -= (NodeFlagsBytes+3) & ~3; // Round up to int boundaries. |
| |
| // Divide the remainder among the nodes! |
| return NumNodes / Pool->NodeSize; |
| } |
| |
| void addToList(PoolSlab **PrevPtrPtr) { |
| PoolSlab *InsertBefore = *PrevPtrPtr; |
| *PrevPtrPtr = this; |
| PrevPtr = PrevPtrPtr; |
| Next = InsertBefore; |
| if (InsertBefore) InsertBefore->PrevPtr = &Next; |
| } |
| |
| void unlinkFromList() { |
| *PrevPtr = Next; |
| if (Next) Next->PrevPtr = PrevPtr; |
| } |
| |
| unsigned getSlabSize() const { |
| return NumNodesInSlab; |
| } |
| |
| // destroy - Release the memory for the current object. |
| void destroy(); |
| |
| // isEmpty - This is a quick check to see if this slab is completely empty or |
| // not. |
| bool isEmpty() const { return UsedEnd == 0; } |
| |
| // isFull - This is a quick check to see if the slab is completely allocated. |
| // |
| bool isFull() const { return isSingleArray || (FirstUnused == getSlabSize()); } |
| |
| // allocateSingle - Allocate a single element from this pool, returning -1 if |
| // there is no space. |
| int allocateSingle(); |
| |
| // allocateMultiple - Allocate multiple contiguous elements from this pool, |
| // returning -1 if there is no space. |
| int allocateMultiple(unsigned Num); |
| |
| // getElementAddress - Return the address of the specified element. |
| void *getElementAddress(unsigned ElementNum, unsigned ElementSize) { |
| char *Data = (char*)&NodeFlagsVector[((unsigned)NumNodesInSlab+15)/16]; |
| return &Data[ElementNum*ElementSize]; |
| } |
| |
| const void *getElementAddress(unsigned ElementNum, unsigned ElementSize)const{ |
| const char *Data = |
| (const char *)&NodeFlagsVector[(unsigned)(NumNodesInSlab+15)/16]; |
| return &Data[ElementNum*ElementSize]; |
| } |
| |
| // containsElement - Return the element number of the specified address in |
| // this slab. If the address is not in slab, return -1. |
| int containsElement(void *Ptr, unsigned ElementSize) const; |
| |
| // freeElement - Free the single node, small array, or entire array indicated. |
| void freeElement(unsigned short ElementIdx); |
| |
| // getSize --- size of an allocation |
| unsigned getSize(void *Node, unsigned ElementSize); |
| |
| // lastNodeAllocated - Return one past the last node in the pool which is |
| // before ScanIdx, that is allocated. If there are no allocated nodes in this |
| // slab before ScanIdx, return 0. |
| unsigned lastNodeAllocated(unsigned ScanIdx); |
| }; |
| |
| // create - Create a new (empty) slab and add it to the end of the Pools list. |
| PoolSlab * |
| PoolSlab::create(PoolTy *Pool) { |
| unsigned NodesPerSlab = getSlabSize(Pool); |
| |
| unsigned Size = sizeof(PoolSlab) + 4*((NodesPerSlab+15)/16) + |
| Pool->NodeSize*getSlabSize(Pool); |
| assert(Size <= PageSize && "Trying to allocate a slab larger than a page!"); |
| PoolSlab *PS = (PoolSlab*)AllocatePage(); |
| |
| PS->NumNodesInSlab = NodesPerSlab; |
| PS->isSingleArray = 0; // Not a single array! |
| PS->FirstUnused = 0; // Nothing allocated. |
| PS->UsedBegin = 0; // Nothing allocated. |
| PS->UsedEnd = 0; // Nothing allocated. |
| PS->allocated = 0; // No bytes allocated. |
| |
| for (unsigned i = 0; i < PS->getSlabSize(); ++i) |
| { |
| PS->markNodeFree(i); |
| PS->clearStartBit(i); |
| } |
| |
| // Add the slab to the list... |
| PS->addToList((PoolSlab**)&Pool->Ptr1); |
| // printf(" creating a slab %x\n", PS); |
| return PS; |
| } |
| |
| void * |
| PoolSlab::createSingleArray(PoolTy *Pool, unsigned NumNodes) { |
| // FIXME: This wastes memory by allocating space for the NodeFlagsVector |
| unsigned NodesPerSlab = getSlabSize(Pool); |
| assert(NumNodes > NodesPerSlab && "No need to create a single array!"); |
| |
| unsigned NumPages = (NumNodes+NodesPerSlab-1)/NodesPerSlab; |
| PoolSlab *PS = (PoolSlab*)AllocateNPages(NumPages); |
| |
| assert(PS && "poolalloc: Could not allocate memory!"); |
| |
| if (Pool->NumSlabs > AddrArrSize) |
| Pool->Slabs->insert((void*)PS); |
| else if (Pool->NumSlabs == AddrArrSize) { |
| // Create the hash_set |
| Pool->Slabs = new hash_set<void *>; |
| Pool->Slabs->insert((void *)PS); |
| for (unsigned i = 0; i < AddrArrSize; ++i) |
| Pool->Slabs->insert((void *) Pool->SlabAddressArray[i]); |
| } else { |
| // Insert it in the array |
| Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) PS; |
| } |
| Pool->NumSlabs++; |
| |
| PS->addToList((PoolSlab**)&Pool->LargeArrays); |
| |
| PS->allocated = 0xffffffff; // No bytes allocated. |
| PS->isSingleArray = 1; |
| PS->NumNodesInSlab = NodesPerSlab; |
| PS->SizeOfSlab = (NumPages * PageSize); |
| *(unsigned*)&PS->FirstUnused = NumPages; |
| return PS->getElementAddress(0, 0); |
| } |
| |
| void |
| PoolSlab::destroy() { |
| if (isSingleArray) |
| for (unsigned NumPages = *(unsigned*)&FirstUnused; NumPages != 1;--NumPages) |
| FreePage((char*)this + (NumPages-1)*PageSize); |
| |
| FreePage(this); |
| } |
| |
| // allocateSingle - Allocate a single element from this pool, returning -1 if |
| // there is no space. |
| int |
| PoolSlab::allocateSingle() { |
| // If the slab is a single array, go on to the next slab. Don't allocate |
| // single nodes in a SingleArray slab. |
| if (isSingleArray) return -1; |
| |
| unsigned SlabSize = getSlabSize(); |
| |
| // Check to see if there are empty entries at the end of the slab... |
| if (UsedEnd < SlabSize) { |
| // Mark the returned entry used |
| unsigned short UE = UsedEnd; |
| markNodeAllocated(UE); |
| setStartBit(UE); |
| |
| // If we are allocating out the first unused field, bump its index also |
| if (FirstUnused == UE) { |
| FirstUnused++; |
| } |
| |
| // Updated the UsedBegin field if necessary |
| if (UsedBegin > UE) UsedBegin = UE; |
| |
| // Return the entry, increment UsedEnd field. |
| ++UsedEnd; |
| assertOkay(); |
| allocated += 1; |
| return UE; |
| } |
| |
| // If not, check to see if this node has a declared "FirstUnused" value that |
| // is less than the number of nodes allocated... |
| // |
| if (FirstUnused < SlabSize) { |
| // Successfully allocate out the first unused node |
| unsigned Idx = FirstUnused; |
| markNodeAllocated(Idx); |
| setStartBit(Idx); |
| |
| // Increment FirstUnused to point to the new first unused value... |
| // FIXME: this should be optimized |
| unsigned short FU = FirstUnused; |
| do { |
| ++FU; |
| } while ((FU != SlabSize) && (isNodeAllocated(FU))); |
| FirstUnused = FU; |
| |
| // Updated the UsedBegin field if necessary |
| if (UsedBegin > Idx) UsedBegin = Idx; |
| |
| assertOkay(); |
| allocated += 1; |
| return Idx; |
| } |
| |
| assertOkay(); |
| return -1; |
| } |
| |
| // allocateMultiple - Allocate multiple contiguous elements from this pool, |
| // returning -1 if there is no space. |
| int |
| PoolSlab::allocateMultiple(unsigned Size) { |
| // Do not allocate small arrays in SingleArray slabs |
| if (isSingleArray) return -1; |
| |
| // For small array allocation, check to see if there are empty entries at the |
| // end of the slab... |
| if (UsedEnd+Size <= getSlabSize()) { |
| // Mark the returned entry used and set the start bit |
| unsigned UE = UsedEnd; |
| setStartBit(UE); |
| for (unsigned i = UE; i != UE+Size; ++i) |
| markNodeAllocated(i); |
| |
| // If we are allocating out the first unused field, bump its index also |
| if (FirstUnused == UE) |
| FirstUnused += Size; |
| |
| // Updated the UsedBegin field if necessary |
| if (UsedBegin > UE) UsedBegin = UE; |
| |
| // Increment UsedEnd |
| UsedEnd += Size; |
| |
| // Return the entry |
| assertOkay(); |
| allocated += Size; |
| return UE; |
| } |
| |
| // If not, check to see if this node has a declared "FirstUnused" value |
| // starting which Size nodes can be allocated |
| // |
| unsigned Idx = FirstUnused; |
| while (Idx+Size <= getSlabSize()) { |
| assert(!isNodeAllocated(Idx) && "FirstUsed is not accurate!"); |
| |
| // Check if there is a continuous array of Size nodes starting FirstUnused |
| unsigned LastUnused = Idx+1; |
| for (; (LastUnused != Idx+Size) && (!isNodeAllocated(LastUnused)); ++LastUnused) |
| /*empty*/; |
| |
| // If we found an unused section of this pool which is large enough, USE IT! |
| if (LastUnused == Idx+Size) { |
| setStartBit(Idx); |
| // FIXME: this loop can be made more efficient! |
| for (unsigned i = Idx; i != Idx + Size; ++i) |
| markNodeAllocated(i); |
| |
| // This should not be allocating on the end of the pool, so we don't need |
| // to bump the UsedEnd pointer. |
| assert(Idx != UsedEnd && "Shouldn't allocate at end of pool!"); |
| |
| // If we are allocating out the first unused field, bump its index also. |
| if (Idx == FirstUnused) { |
| unsigned SlabSize = getSlabSize(); |
| unsigned i; |
| for (i = FirstUnused+Size; i < UsedEnd; ++i) { |
| if (!isNodeAllocated(i)) { |
| break; |
| } |
| } |
| FirstUnused = i; |
| if (isNodeAllocated(i)) |
| FirstUnused = SlabSize; |
| } |
| |
| // Updated the UsedBegin field if necessary |
| if (UsedBegin > Idx) UsedBegin = Idx; |
| |
| // Return the entry |
| assertOkay(); |
| allocated += Size; |
| return Idx; |
| } |
| |
| // Otherwise, try later in the pool. Find the next unused entry. |
| Idx = LastUnused; |
| while (Idx+Size <= getSlabSize() && isNodeAllocated(Idx)) |
| ++Idx; |
| } |
| |
| assertOkay(); |
| return -1; |
| } |
| |
| // getSize |
| unsigned PoolSlab::getSize(void *Ptr, unsigned ElementSize) { |
| if (isSingleArray) abort(); |
| const void *FirstElement = getElementAddress(0, 0); |
| if (FirstElement <= Ptr) { |
| unsigned Delta = (char*)Ptr-(char*)FirstElement; |
| unsigned Index = Delta/ElementSize; |
| |
| if (Index < getSlabSize()) { |
| //we have the index now do something like free |
| assert(isStartOfAllocation(Index) && |
| "poolrealloc: Attempt to realloc from the middle of allocated array\n"); |
| unsigned short ElementEndIdx = Index + 1; |
| |
| // FIXME: This should use manual strength reduction to produce decent code. |
| unsigned short UE = UsedEnd; |
| while (ElementEndIdx != UE && |
| !isStartOfAllocation(ElementEndIdx) && |
| isNodeAllocated(ElementEndIdx)) { |
| ++ElementEndIdx; |
| } |
| return (ElementEndIdx - Index); |
| } |
| } |
| if (logregs) |
| { |
| fprintf(stderr, "PoolSlab::getSize failed!\n"); |
| fflush(stderr); |
| } |
| abort(); |
| } |
| |
| |
| // containsElement - Return the element number of the specified address in |
| // this slab. If the address is not in slab, return -1. |
| int |
| PoolSlab::containsElement(void *Ptr, unsigned ElementSize) const { |
| const void *FirstElement = getElementAddress(0, 0); |
| if (FirstElement <= Ptr) { |
| unsigned Delta = (char*)Ptr-(char*)FirstElement; |
| if (isSingleArray) { |
| if (Delta < SizeOfSlab) return Delta/ElementSize; |
| } |
| unsigned Index = Delta/ElementSize; |
| if (Index < getSlabSize()) { |
| if (Delta % ElementSize != 0) { |
| fprintf(stderr, "Freeing pointer into the middle of an element!\n"); |
| fflush(stderr); |
| abort(); |
| } |
| |
| return Index; |
| } |
| } |
| return -1; |
| } |
| |
| |
| // freeElement - Free the single node, small array, or entire array indicated. |
| void |
| PoolSlab::freeElement(unsigned short ElementIdx) { |
| if (!isNodeAllocated(ElementIdx)) return; |
| // assert(isNodeAllocated(ElementIdx) && |
| // "poolfree: Attempt to free node that is already freed\n"); |
| #if 0 |
| assert(!isSingleArray && "Cannot free an element from a single array!"); |
| #else |
| #if 0 |
| if (isSingleArray) { |
| this->addToList((PoolSlab**)&Pool->FreeLargeArrays); |
| return; |
| } |
| #endif |
| #endif |
| |
| // Mark this element as being free! |
| markNodeFree(ElementIdx); |
| --allocated; |
| |
| // If this slab is not a SingleArray |
| assert(isStartOfAllocation(ElementIdx) && |
| "poolfree: Attempt to free middle of allocated array\n"); |
| |
| // Free the first cell |
| clearStartBit(ElementIdx); |
| markNodeFree(ElementIdx); |
| |
| // Free all nodes if this was a small array allocation. |
| unsigned short ElementEndIdx = ElementIdx + 1; |
| |
| // FIXME: This should use manual strength reduction to produce decent code. |
| unsigned short UE = UsedEnd; |
| while (ElementEndIdx != UE && |
| !isStartOfAllocation(ElementEndIdx) && |
| isNodeAllocated(ElementEndIdx)) { |
| markNodeFree(ElementEndIdx); |
| --allocated; |
| ++ElementEndIdx; |
| } |
| |
| // Update the first free field if this node is below the free node line |
| if (ElementIdx < FirstUnused) FirstUnused = ElementIdx; |
| |
| // Update the first used field if this node was the first used. |
| if (ElementIdx == UsedBegin) UsedBegin = ElementEndIdx; |
| |
| // If we are freeing the last element in a slab, shrink the UsedEnd marker |
| // down to the last used node. |
| if (ElementEndIdx == UE) { |
| #if 0 |
| printf("FU: %d, UB: %d, UE: %d FREED: [%d-%d)", |
| FirstUnused, UsedBegin, UsedEnd, ElementIdx, ElementEndIdx); |
| #endif |
| |
| // If the user is freeing the slab entirely in-order, it's quite possible |
| // that all nodes are free in the slab. If this is the case, simply reset |
| // our pointers. |
| if (UsedBegin == UE) { |
| FirstUnused = 0; |
| UsedBegin = 0; |
| UsedEnd = 0; |
| assertOkay(); |
| } else if (FirstUnused == ElementIdx) { |
| // Freed the last node(s) in this slab. |
| FirstUnused = ElementIdx; |
| UsedEnd = ElementIdx; |
| assertOkay(); |
| } else { |
| UsedEnd = lastNodeAllocated(ElementIdx); |
| if (FirstUnused > UsedEnd) FirstUnused = UsedEnd; |
| assertOkay(); |
| assert(FirstUnused <= UsedEnd+1 && |
| "FirstUnused field was out of date!"); |
| } |
| } |
| assertOkay(); |
| } |
| |
| unsigned |
| PoolSlab::lastNodeAllocated(unsigned ScanIdx) { |
| // Check the last few nodes in the current word of flags... |
| unsigned CurWord = ScanIdx/16; |
| unsigned short Flags = NodeFlagsVector[CurWord] & 0xFFFF; |
| if (Flags) { |
| // Mask off nodes above this one |
| Flags &= (1 << ((ScanIdx & 15)+1))-1; |
| if (Flags) { |
| // If there is still something in the flags vector, then there is a node |
| // allocated in this part. The goto is a hack to get the uncommonly |
| // executed code away from the common code path. |
| //printf("A: "); |
| goto ContainsAllocatedNode; |
| } |
| } |
| |
| // Ok, the top word doesn't contain anything, scan the whole flag words now. |
| --CurWord; |
| while (CurWord != ~0U) { |
| Flags = NodeFlagsVector[CurWord] & 0xFFFF; |
| if (Flags) { |
| // There must be a node allocated in this word! |
| //printf("B: "); |
| goto ContainsAllocatedNode; |
| } |
| CurWord--; |
| } |
| return 0; |
| |
| ContainsAllocatedNode: |
| // Figure out exactly which node is allocated in this word now. The node |
| // allocated is the one with the highest bit set in 'Flags'. |
| // |
| // This should use __builtin_clz to get the value, but this builtin is only |
| // available with GCC 3.4 and above. :( |
| assert(Flags && "Should have allocated node!"); |
| |
| unsigned short MSB; |
| #if GCC3_4_EVENTUALLY |
| MSB = 16 - ::__builtin_clz(Flags); |
| #else |
| for (MSB = 15; (Flags & (1U << MSB)) == 0; --MSB) |
| /*empty*/; |
| #endif |
| |
| assert((1U << MSB) & Flags); // The bit should be set |
| assert((~(1U << MSB) & Flags) < Flags);// Removing it should make flag smaller |
| ScanIdx = CurWord*16 + MSB; |
| assert(isNodeAllocated(ScanIdx)); |
| return (ScanIdx+1); |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // StackSlab implementation |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // |
| // Structure: StackSlab |
| // |
| // Description: |
| // A stack slab is similar to a pool slab but simple and smaller. It is used |
| // for stack allocations that have been promoted to the heap. |
| struct StackSlab { |
| public: |
| // Pointer to canonical address of stack slab |
| StackSlab * Canonical; |
| |
| // Pointers for linking in the stack slab |
| StackSlab **PrevPtr, *Next; |
| |
| // Top of stack |
| unsigned int * tos; |
| |
| // Data for the stack |
| unsigned int data[1020]; |
| |
| static StackSlab *create (void * p) { |
| StackSlab *SS = (StackSlab*) p; |
| SS->tos = &(SS->data[0]); |
| return SS; |
| } |
| |
| unsigned char * allocate (unsigned int size) { |
| // |
| // We will return a pointer to the current top of stack. |
| // |
| unsigned char * retvalue = (unsigned char *) (tos); |
| |
| // |
| // Adjust the top of stack down to the next free object. |
| // |
| size = (size + 3) & (~3u); |
| unsigned int NumberOfInts = size / sizeof (unsigned int); |
| tos += NumberOfInts; |
| assert (tos < &(data[1020])); |
| return retvalue; |
| } |
| |
| void clear (void) { |
| tos = data; |
| } |
| |
| void addToList(StackSlab **PrevPtrPtr) { |
| StackSlab *InsertBefore = *PrevPtrPtr; |
| *PrevPtrPtr = this; |
| PrevPtr = PrevPtrPtr; |
| Next = InsertBefore; |
| if (InsertBefore) InsertBefore->PrevPtr = &Next; |
| } |
| |
| void unlinkFromList() { |
| *PrevPtr = Next; |
| if (Next) Next->PrevPtr = PrevPtr; |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // Pool allocator library implementation |
| // |
| //===----------------------------------------------------------------------===// |
| |
| void |
| pool_init_runtime (unsigned Dangling) { |
| // |
| // Configure the allocator. |
| // |
| extern ConfigData ConfigData; |
| ConfigData.RemapObjects = Dangling; |
| |
| // |
| // Allocate a range of memory for rewrite pointers. |
| // |
| #if !defined(__linux__) |
| const unsigned invalidsize = 1 * 1024 * 1024 * 1024; |
| void * Addr = mmap (0, invalidsize, 0, MAP_SHARED | MAP_ANON, -1, 0); |
| if (Addr == MAP_FAILED) { |
| perror ("mmap:"); |
| fflush (stdout); |
| fflush (stderr); |
| assert(0 && "valloc failed\n"); |
| } |
| madvise (Addr, invalidsize, MADV_FREE); |
| InvalidLower = (unsigned int) Addr; |
| InvalidUpper = (unsigned int) Addr + invalidsize; |
| #endif |
| |
| // |
| // Install hooks for catching allocations outside the scope of SAFECode |
| // |
| #if 0 |
| extern void installAllocHooks(void); |
| installAllocHooks(); |
| #endif |
| return; |
| } |
| |
| // poolinit - Initialize a pool descriptor to empty |
| // |
| void |
| poolinit(PoolTy *Pool, unsigned NodeSize) { |
| assert(Pool && "Null pool pointer passed into poolinit!\n"); |
| DEBUG(printf("pool init %x, %d\n", Pool, NodeSize);) |
| |
| // Ensure the page manager is initialized |
| InitializePageManager(); |
| |
| // We must alway return unique pointers, even if they asked for 0 bytes |
| Pool->NodeSize = NodeSize ? NodeSize : 1; |
| // Initialize the splay tree |
| Pool->Objects = Pool->OOB = Pool->DPTree = 0; |
| Pool->DPTree = 0; |
| Pool->Ptr1 = Pool->Ptr2 = 0; |
| Pool->LargeArrays = 0; |
| Pool->StackSlabs = Pool->FreeStackSlabs = 0; |
| // For SAFECode, we set FreeablePool to 0 always |
| // Pool->FreeablePool = 0; |
| Pool->AllocadPool = -1; |
| Pool->allocaptr = 0; |
| Pool->lastUsed = 0; |
| Pool->prevPage[0] = 0; |
| Pool->prevPage[1] = 0; |
| // Initialize the SlabAddressArray to zero |
| for (int i = 0; i < AddrArrSize; ++i) { |
| Pool->SlabAddressArray[i] = 0; |
| } |
| Pool->NumSlabs = 0; |
| #if 0 |
| Pool->RegNodes = new std::map<void*,unsigned>; |
| #endif |
| |
| if (dummyInitialized == 1) |
| return; |
| |
| dummyPool.NodeSize = NodeSize ? NodeSize : 1; |
| // Initialize the splay tree |
| dummyPool.Objects = dummyPool.OOB = dummyPool.DPTree = 0; |
| dummyPool.Ptr1 = dummyPool.Ptr2 = 0; |
| dummyPool.LargeArrays = 0; |
| // For SAFECode, we set FreeablePool to 0 always |
| // Pool->FreeablePool = 0; |
| dummyPool.AllocadPool = -1; |
| dummyPool.allocaptr = 0; |
| dummyPool.lastUsed = 0; |
| dummyPool.prevPage[0] = 0; |
| dummyPool.prevPage[1] = 0; |
| // Initialize the SlabAddressArray to zero |
| for (int i = 0; i < AddrArrSize; ++i) { |
| dummyPool.SlabAddressArray[i] = 0; |
| } |
| dummyPool.NumSlabs = 0; |
| #if 0 |
| dummyPool.RegNodes = new std::map<void*,unsigned>; |
| #endif |
| dummyInitialized = 1; |
| } |
| |
| void |
| poolmakeunfreeable(PoolTy *Pool) { |
| assert(Pool && "Null pool pointer passed in to poolmakeunfreeable!\n"); |
| // Pool->FreeablePool = 0; |
| } |
| |
| // pooldestroy - Release all memory allocated for a pool |
| // |
| // FIXME: determine how to adjust debug logs when |
| // pooldestroy is called |
| void |
| pooldestroy(PoolTy *Pool) { |
| assert(Pool && "Null pool pointer passed in to pooldestroy!\n"); |
| adl_splay_delete_tag(&Pool->Objects, Pool); |
| //adl_splay_delete_tag(&Pool->DPTree, Pool); |
| if (Pool->AllocadPool) return; |
| |
| // Remove all registered pools |
| #if 0 |
| delete Pool->RegNodes; |
| #endif |
| |
| if (Pool->NumSlabs > AddrArrSize) { |
| Pool->Slabs->clear(); |
| delete Pool->Slabs; |
| } |
| |
| // Free any partially allocated slabs |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| while (PS) { |
| PoolSlab *Next = PS->Next; |
| PS->destroy(); |
| PS = Next; |
| } |
| |
| // Free the completely allocated slabs |
| PS = (PoolSlab*)Pool->Ptr2; |
| while (PS) { |
| PoolSlab *Next = PS->Next; |
| PS->destroy(); |
| PS = Next; |
| } |
| |
| // Free the large arrays |
| PS = (PoolSlab*)Pool->LargeArrays; |
| while (PS) { |
| PoolSlab *Next = PS->Next; |
| PS->destroy(); |
| PS = Next; |
| } |
| |
| } |
| |
| |
| // Function: poolallocarray() |
| // |
| // Description: |
| // This is a helper function used to implement poolalloc() when the number of |
| // nodes to allocate is not 1. |
| // |
| // Inputs: |
| // Pool - A pointer to the pool from which to allocate. |
| // Size - The number of nodes to allocate. |
| // |
| // FIXME: look into globalTemp, make it a pass by reference arg instead of |
| // a global variable. |
| // FIXME: determine whether Size is bytes or number of nodes. |
| static void * |
| poolallocarray(PoolTy* Pool, unsigned Size) { |
| assert(Pool && "Null pool pointer passed into poolallocarray!\n"); |
| |
| // check to see if we need to allocate a single large array |
| if (Size > PoolSlab::getSlabSize(Pool)) { |
| if (logregs) { |
| fprintf(stderr, " poolallocarray:694: Size = %d, SlabSize = %d\n", Size, PoolSlab::getSlabSize(Pool)); |
| fflush(stderr); |
| } |
| globalTemp = (PoolSlab*) PoolSlab::createSingleArray(Pool, Size); |
| unsigned offset = (unsigned)globalTemp & (PPageSize - 1); |
| void * retAddress = (void *)((unsigned)(globalTemp) & ~(PPageSize - 1)); |
| |
| if (logregs) { |
| fprintf(stderr, " poolallocarray:704: globalTemp = 0x%08x, offset = 0x%08x, retAddress = 0x%08x\n", |
| (unsigned)globalTemp, offset, (unsigned)retAddress); |
| fflush(stderr); |
| } |
| return (void*) ((unsigned)retAddress + offset); |
| } |
| |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| unsigned offset; |
| |
| // Loop through all of the slabs looking for one with an opening |
| for (; PS; PS = PS->Next) { |
| int Element = PS->allocateMultiple(Size); |
| if (Element != -1) { |
| // We allocated an element. Check to see if this slab has been completely |
| // filled up. If so, move it to the Ptr2 list. |
| if (PS->isFull()) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| |
| // insert info into adl splay tree for poolcheck runtime |
| //unsigned NodeSize = Pool->NodeSize; |
| globalTemp = PS->getElementAddress(Element, Pool->NodeSize); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| //adl_splay_insert(&(Pool->Objects), globalTemp, |
| // (unsigned)((Size*NodeSize) - NodeSize + 1), (Pool)); |
| if(logregs) {fprintf(stderr, " poolallocarray:731:before RemapObject\n");} |
| // remap the page to get a shadow page (dangling pointer detection library) |
| PS = (PoolSlab *) RemapObject(globalTemp, Size*Pool->NodeSize); |
| if (logregs) { |
| fprintf(stderr, " poolallocarray:735: globalTemp = 0x%x\n", (unsigned)globalTemp); |
| fprintf(stderr ," poolallocarray:736: PS = 0x%08x, offset = 0x%08x, retAddress = 0x%08x\n", |
| (unsigned)PS, offset, (unsigned)PS + offset); |
| } |
| return (void*) ((unsigned)PS + offset); |
| } |
| } |
| |
| PoolSlab *New = PoolSlab::create(Pool); |
| // printf("new slab created %x \n", New); |
| if (Pool->NumSlabs > AddrArrSize) |
| Pool->Slabs->insert((void *)New); |
| else if (Pool->NumSlabs == AddrArrSize) { |
| // Create the hash_set |
| Pool->Slabs = new hash_set<void *>; |
| Pool->Slabs->insert((void *)New); |
| for (unsigned i = 0; i < AddrArrSize; ++i) |
| Pool->Slabs->insert((void *)Pool->SlabAddressArray[i]); |
| } |
| else { |
| // Insert it in the array |
| Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) New; |
| } |
| |
| Pool->NumSlabs++; |
| |
| int Idx = New->allocateMultiple(Size); |
| assert(Idx == 0 && "New allocation didn't return zero'th node?"); |
| |
| // insert info into adl splay tree for poolcheck runtime |
| //unsigned NodeSize = Pool->NodeSize; |
| globalTemp = New->getElementAddress(0, 0); |
| //adl_splay_insert(&(Pool->Objects), globalTemp, |
| // (unsigned)((Size*NodeSize) - NodeSize + 1), (Pool)); |
| |
| // remap page to get a shadow page (dangling pointer detection library) |
| New = (PoolSlab *) RemapObject(globalTemp, Size*Pool->NodeSize); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| if (logregs) { |
| fprintf(stderr, " poolallocarray:774: globalTemp = 0x%x\n, offset = 0x%x\n", (unsigned)globalTemp, offset); |
| fprintf(stderr, " poolallocarray:775: New = 0x%08x, Size = %d, retAddress = 0x%08x\n", |
| (unsigned)New, Size, (unsigned)New + offset); |
| } |
| return (void*) ((unsigned)New + offset); |
| } |
| |
| void |
| poolregister(PoolTy *Pool, void * allocaptr, unsigned NumBytes) { |
| // If the pool is NULL, don't do anything. |
| if (!Pool) return; |
| |
| #if 0 |
| if (Pool->AllocadPool != -1) { |
| if (Pool->AllocadPool == 0) { |
| printf(" Handle this case later\n"); |
| exit(-1); |
| } else { |
| printf(" An allocad pool, you can only allocate once \n"); |
| exit(-1); |
| } |
| } else { |
| Pool->AllocadPool = NumBytes; |
| Pool->allocaptr = allocaptr; |
| } |
| #else |
| #if 0 |
| Pool->RegNodes->insert (std::make_pair(allocaptr,NumBytes)); |
| #endif |
| adl_splay_insert(&(Pool->Objects), allocaptr, NumBytes, 0); |
| if (logregs) { |
| fprintf (stderr, "poolregister: %x %d\n", (unsigned)allocaptr, NumBytes); |
| } |
| #endif |
| } |
| |
| void |
| poolunregister(PoolTy *Pool, void * allocaptr) { |
| if (!Pool) return; |
| adl_splay_delete(&Pool->Objects, allocaptr); |
| if (logregs) { |
| fprintf (stderr, "pooluregister: %x\n", allocaptr); |
| } |
| } |
| |
| extern "C" void frag(PoolTy * Pool); |
| void |
| frag(PoolTy * Pool) { |
| unsigned long totalalloc=0; |
| unsigned long total=0; |
| for (PoolSlab *PS = (PoolSlab*)Pool->Ptr1; PS; PS = PS->Next) { |
| total += PS->getSlabSize(); |
| totalalloc += PS->allocated; |
| fprintf (stderr, "%2f\n", (double) PS->allocated * 100 / (double) PS->getSlabSize()); |
| } |
| fprintf (stderr, "%d %d %2f\n", totalalloc, total, (double) totalalloc * 100 / (double) total); |
| fflush (stderr); |
| } |
| |
| //Pool->AllocadPool -1 : unused so far |
| //Pool->AllocadPool 0 : used only for mallocs |
| //Pool->AllocadPool >0 : used for only allocas indicating the size |
| void * |
| poolalloc(PoolTy *Pool, unsigned NumBytes) { |
| void *retAddress = NULL; |
| assert(Pool && "Null pool pointer passed into poolalloc!\n"); |
| |
| #if 0 |
| // Ensure that stack objects and heap objects d not belong to the same pool. |
| if (Pool->AllocadPool != -1) { |
| if (Pool->AllocadPool != 0) { |
| printf(" Did not Handle this case, an alloa and malloc point to"); |
| printf("same DSNode, Will happen in stack safety \n"); |
| exit(-1); |
| } |
| } |
| else { |
| Pool->AllocadPool = 0; |
| } |
| #endif |
| |
| // Ensure that we're always allocating at least 1 byte. |
| if (NumBytes == 0) |
| NumBytes = 1; |
| |
| unsigned NodeSize = Pool->NodeSize; |
| unsigned NodesToAllocate = (NumBytes + NodeSize - 1)/NodeSize; |
| unsigned offset = 0; |
| PDebugMetaData debugmetadataPtr; |
| |
| // Call a helper function if we need to allocate more than 1 node. |
| if (NodesToAllocate > 1) { |
| if (logregs) { |
| fprintf(stderr, " poolalloc:848: Allocating more than 1 node for %d bytes\n", NumBytes); fflush(stderr); |
| } |
| retAddress = poolallocarray(Pool, NodesToAllocate); |
| |
| // |
| // Record information about this allocation in the global debugging |
| // structure. |
| globalallocID++; |
| debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, __builtin_return_address(0), 0, globalTemp); |
| adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, (void *) debugmetadataPtr); |
| if (logregs) { |
| fprintf(stderr, " poolalloc:856: after inserting to dummyPool\n"); |
| fflush (stderr); |
| } |
| |
| // Register the object in the splay tree. Keep track of its debugging data |
| // with the splay node tag so that we can quickly map shadow address back |
| // to the canonical address. |
| // |
| // globalTemp is the canonical page address |
| adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr); |
| |
| //if ((unsigned)retAddress > 0x2f000000 && logregs == 0) |
| // logregs = 1; |
| |
| if (logregs) { |
| fprintf(stderr, " poolalloc:863: retAddress = 0x%08x NumBytes = %d globalTemp = 0x%08x\n", |
| (unsigned)retAddress, NumBytes, (unsigned)globalTemp); fflush(stderr); |
| } |
| assert (retAddress && "poolalloc(1): Returning NULL!\n"); |
| return retAddress; |
| } |
| // Special case the most common situation, where a single node is being |
| // allocated. |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| |
| if (__builtin_expect(PS != 0, 1)) { |
| int Element = PS->allocateSingle(); |
| if (__builtin_expect(Element != -1, 1)) { |
| // We allocated an element. Check to see if this slab has been |
| // completely filled up. If so, move it to the Ptr2 list. |
| if (__builtin_expect(PS->isFull(), false)) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| |
| globalTemp = PS->getElementAddress(Element, NodeSize); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| if (logregs) { |
| fprintf(stderr, " poolalloc:885: canonical page = 0x%08x offset = 0x%08x\n", (unsigned)globalTemp, offset); |
| } |
| //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool)); |
| |
| // remap page to get a shadow page for dangling pointer library |
| PS = (PoolSlab *) RemapObject(globalTemp, NumBytes); |
| retAddress = (void*) ((unsigned)PS + offset); |
| // for the use of dangling pointer runtime |
| globalallocID++; |
| debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, |
| __builtin_return_address(0), 0, globalTemp); |
| adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, debugmetadataPtr); |
| |
| adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr); |
| if (logregs) { |
| fprintf(stderr, " poolalloc:900: retAddress = 0x%08x, NumBytes = %d\n", (unsigned)retAddress, NumBytes); |
| } |
| assert (retAddress && "poolalloc(2): Returning NULL!\n"); |
| return retAddress; |
| } |
| |
| // Loop through all of the slabs looking for one with an opening |
| for (PS = PS->Next; PS; PS = PS->Next) { |
| int Element = PS->allocateSingle(); |
| if (Element != -1) { |
| // We allocated an element. Check to see if this slab has been |
| // completely filled up. If so, move it to the Ptr2 list. |
| if (PS->isFull()) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| |
| globalTemp = PS->getElementAddress(Element, NodeSize); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool)); |
| |
| // remap page to get a shadow page for dangling pointer library |
| PS = (PoolSlab *) RemapObject(globalTemp, NumBytes); |
| retAddress = (void*) ((unsigned)PS + offset); |
| //printf(" returning the address %x",retAddress); |
| // for the use of dangling pointer runtime |
| globalallocID++; |
| debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, |
| __builtin_return_address(0), 0, globalTemp); |
| adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, debugmetadataPtr); |
| |
| adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr); |
| if (logregs) { |
| fprintf (stderr, " poolalloc:932: PS = 0x%08x, retAddress = 0x%08x, NumBytes = %d, offset = 0x%08x\n", |
| (unsigned)PS, (unsigned)retAddress, NumBytes, offset); |
| } |
| assert (retAddress && "poolalloc(3): Returning NULL!\n"); |
| return retAddress; |
| } |
| } |
| } |
| |
| // Otherwise we must allocate a new slab and add it to the list |
| PoolSlab *New = PoolSlab::create(Pool); |
| // |
| // Ensure that we're always allocating at least 1 byte. |
| // |
| if (NumBytes == 0) |
| NumBytes = 1; |
| |
| if (Pool->NumSlabs > AddrArrSize) |
| Pool->Slabs->insert((void *)New); |
| else if (Pool->NumSlabs == AddrArrSize) { |
| // Create the hash_set |
| Pool->Slabs = new hash_set<void *>; |
| Pool->Slabs->insert((void *)New); |
| for (unsigned i = 0; i < AddrArrSize; ++i) |
| Pool->Slabs->insert((void *)Pool->SlabAddressArray[i]); |
| } |
| else { |
| // Insert it in the array |
| Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) New; |
| } |
| Pool->NumSlabs++; |
| |
| |
| int Idx = New->allocateSingle(); |
| assert(Idx == 0 && "New allocation didn't return zero'th node?"); |
| if (logregs) { |
| fprintf(stderr, " poolalloc:967: canonical page at 0x%08x from underlying allocator\n", (unsigned)New); |
| } |
| globalTemp = New->getElementAddress(0, 0); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| |
| if (logregs) { |
| fprintf(stderr, " poolalloc:973: element at 0x%08x, offset=0x%08x\n", (unsigned)globalTemp, offset); |
| } |
| //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool)); |
| |
| // remap page to get a shadow page for dangling pointer library |
| New = (PoolSlab *) RemapObject(globalTemp, NumBytes); |
| offset = (unsigned)globalTemp & (PPageSize - 1); |
| //printf(" shadow page at 0x%x through remapping\n", (unsigned)New); |
| retAddress = (void*) ((unsigned)New + offset); |
| //printf(" returning the address 0x%x\n", (unsigned)retAddress); |
| // for the use of dangling pointer runtime |
| globalallocID++; |
| debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, __builtin_return_address(0), 0, globalTemp); |
| adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, (void *) debugmetadataPtr); |
| |
| adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr); |
| if (logregs) { |
| fprintf (stderr, " poolalloc:990: New = 0x%08x, retAddress = 0x%08x, NumBytes = %d, offset = 0x%08x\n", |
| (unsigned)New, (unsigned)retAddress, NumBytes, offset); |
| } |
| assert (retAddress && "poolalloc(4): Returning NULL!\n"); |
| return retAddress; |
| } |
| |
| void * |
| poolrealloc(PoolTy *Pool, void *Node, unsigned NumBytes) { |
| if (Node == 0) return poolalloc(Pool, NumBytes); |
| if (NumBytes == 0) { |
| poolfree(Pool, Node); |
| return 0; |
| } |
| |
| void *New = poolalloc(Pool, NumBytes); |
| // unsigned Size = |
| //FIXME the following may not work in all cases |
| memcpy(New, Node, NumBytes); |
| poolfree(Pool, Node); |
| return New; |
| } |
| |
| void * |
| poolcalloc (PoolTy *Pool, unsigned Number, unsigned NumBytes) { |
| void * New = poolalloc (Pool, Number * NumBytes); |
| if (New) bzero (New, Number * NumBytes); |
| return New; |
| } |
| |
| void * |
| poolstrdup(PoolTy *Pool, char *Node) { |
| if (Node == 0) return 0; |
| |
| unsigned int NumBytes = strlen(Node) + 1; |
| void *New = poolalloc(Pool, NumBytes); |
| if (New) { |
| memcpy(New, Node, NumBytes+1); |
| } |
| return New; |
| } |
| |
| // |
| // Function: pool_newstack() |
| // |
| // Description: |
| // Create a new pool slab for the given function invocation. |
| // |
| void |
| pool_newstack (PoolTy * Pool) { |
| // Pointer to the new pool slab |
| StackSlab * PS; |
| |
| // |
| // Get a new stack slab. Either reuse an old one or create a new one. |
| // |
| assert ((sizeof (StackSlab) <= 4096) && "StackSlab too big!\n"); |
| if (Pool->FreeStackSlabs) { |
| PS = (StackSlab *)(Pool->FreeStackSlabs); |
| PS->unlinkFromList(); |
| } else { |
| PS = (StackSlab*) valloc (sizeof (StackSlab)); |
| } |
| |
| // |
| // Ensure we have a pool slab. |
| // |
| assert (PS && "pool_newstack: Can't create new slab\n"); |
| |
| // |
| // Remap the stack slab into a new virtual address space. |
| // |
| PS->Canonical = PS; |
| PS = (StackSlab *) RemapObject (PS, sizeof (StackSlab)); |
| |
| // |
| // Initialize it. |
| // |
| PS = StackSlab::create (PS); |
| |
| // |
| // Link the shadow slab into the set of stack slabs. |
| // |
| PS->addToList((StackSlab**)&Pool->StackSlabs); |
| #if 1 |
| fprintf (stderr, "\nnewstack: %x %x\n", PS, PS->Canonical); |
| fflush (stderr); |
| #endif |
| return; |
| } |
| |
| void * |
| pool_alloca (PoolTy * Pool, unsigned int NumBytes) { |
| // The address of the allocated object |
| void * retAddress; |
| |
| // Ensure that we're always allocating at least 1 byte. |
| if (NumBytes == 0) |
| NumBytes = 1; |
| |
| // Allocate memory from the function's single slab. |
| assert (Pool->StackSlabs && "pool_alloca: No call to newstack!\n"); |
| globalTemp = ((StackSlab *)(Pool->StackSlabs))->allocate (NumBytes); |
| fprintf (stderr, "alloca: %x %x\n", globalTemp, NumBytes); |
| fflush (stderr); |
| |
| // |
| // Allocate and remap the object. |
| // |
| retAddress = globalTemp; |
| |
| // |
| // Record information about this allocation in the global debugging |
| // structure. |
| // FIXME: Need to ensure MetaData is correct for debugging |
| // |
| globalallocID++; |
| PDebugMetaData debugmetadataPtr; |
| debugmetadataPtr = createPtrMetaData (globalallocID, |
| globalfreeID, |
| __builtin_return_address(0), |
| 0, |
| globalTemp); |
| |
| adl_splay_insert (&(dummyPool.DPTree), |
| retAddress, |
| NumBytes, |
| (void *) debugmetadataPtr); |
| |
| // Register the object in the splay tree. Keep track of its debugging data |
| // with the splay node tag so that we can quickly map shadow address back |
| // to the canonical address. |
| // |
| // globalTemp is the canonical page address |
| adl_splay_insert (&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr); |
| |
| assert (retAddress && "pool_alloca(1): Returning NULL!\n"); |
| return retAddress; |
| } |
| |
| void |
| pool_delstack (PoolTy * Pool) { |
| StackSlab * PS = (StackSlab *)(Pool->StackSlabs); |
| |
| // |
| // Get the canonical page corresponding to this slab. |
| // |
| #if 1 |
| fprintf (stderr, "delstack: %x\n", PS); |
| fflush (stderr); |
| #endif |
| |
| // |
| // Remove the slab from the list. |
| // |
| PS->unlinkFromList(); |
| |
| // |
| // Deallocate all elements and add the slab into the set of free slabs. |
| // |
| PS->Canonical->addToList((StackSlab**)&Pool->FreeStackSlabs); |
| |
| #if 1 |
| // |
| // Make the stack page inaccessible. |
| // |
| ProtectShadowPage (PS, 1); |
| #endif |
| |
| return; |
| } |
| |
| // SearchForContainingSlab - Do a brute force search through the list of |
| // allocated slabs for the node in question. |
| // |
| static PoolSlab * |
| SearchForContainingSlab(PoolTy *Pool, void *Node, unsigned &TheIndex) { |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| unsigned NodeSize = Pool->NodeSize; |
| |
| // Search the partially allocated slab list for the slab that contains this |
| // node. |
| int Idx = -1; |
| if (PS) { // Pool->Ptr1 could be null if Ptr2 isn't |
| for (; PS; PS = PS->Next) { |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| } |
| } |
| |
| // If the partially allocated slab list doesn't contain it, maybe the |
| // completely allocated list does. |
| if (PS == 0) { |
| PS = (PoolSlab*)Pool->Ptr2; |
| assert(Idx == -1 && "Found node but don't have PS?"); |
| |
| while (PS) { |
| assert(PS && "poolfree: node being free'd not found in allocation " |
| " pool specified!\n"); |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| PS = PS->Next; |
| } |
| } |
| |
| // Otherwise, maybe its a block within LargeArrays |
| if(PS == 0) { |
| PS = (PoolSlab*)Pool->LargeArrays; |
| assert(Idx == -1 && "Found node but don't have PS?"); |
| |
| while (PS) { |
| assert(PS && "poolfree: node being free'd not found in allocation " |
| " pool specified!\n"); |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| PS = PS->Next; |
| } |
| } |
| |
| TheIndex = Idx; |
| return PS; |
| } |
| |
| void |
| poolcheck(PoolTy *Pool, void *Node) { |
| void* S = Node; |
| unsigned len = 0; |
| if (!Pool) return; |
| int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0); |
| if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) { |
| return; |
| } |
| |
| /* |
| * The node is not found or is not within bounds; fail! |
| */ |
| fprintf (stderr, "Poolcheck failed(%x:%x): %x %x from %x\n", |
| (unsigned)Pool, fs, (unsigned)Node, len, (unsigned)__builtin_return_address(0)); |
| fflush (stderr); |
| abort (); |
| return; |
| } |
| |
| void |
| poolcheckui (PoolTy *Pool, void *Node) { |
| void* S = Node; |
| unsigned len = 0; |
| if (!Pool) return; |
| |
| /* |
| * Look for the object within the pool's splay tree. |
| */ |
| int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0); |
| if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) { |
| return; |
| } |
| |
| /* |
| * Look for the object within the splay tree of external objects. |
| */ |
| S = Node; |
| len = 0; |
| fs = adl_splay_retrieve (&(ExternalObjects), &S, &len, 0); |
| if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) { |
| return; |
| } |
| |
| /* |
| * The node is not found or is not within bounds. Report a warning but keep |
| * going. |
| */ |
| fprintf (stderr, "PoolcheckUI failed(%x:%x): %x %x from %x\n", |
| (unsigned)Pool, fs, (unsigned)Node, len, (unsigned)__builtin_return_address(0)); |
| fflush (stderr); |
| return; |
| } |
| |
| /* |
| * Function: boundscheck() |
| * |
| * Description: |
| * Perform a precise bounds check. Ensure that Source is within a valid |
| * object within the pool and that Dest is within the bounds of the same |
| * object. |
| */ |
| static unsigned char * invalidptr = 0; |
| |
| void * |
| boundscheck (PoolTy * Pool, void * Source, void * Dest) { |
| void* S = Source; |
| unsigned len = 0; |
| int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0); |
| if ((fs) && (S <= Dest) && (((char*)S + len) > (char*)Dest)) { |
| return Dest; |
| } |
| |
| /* |
| * Handle the case where a pointer is allowed to move just beyond the end of |
| * the allocated space. |
| */ |
| if ((fs) && (((char *) Dest) == ((char*)S + len))) { |
| if (logregs) |
| fprintf (stderr, "boundscheck : rewrite: %x %x %x %x, pc=%x\n", |
| S, Source, Dest, len, (void*)__builtin_return_address(0)); |
| if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower; |
| ++invalidptr; |
| void* P = invalidptr; |
| if ((unsigned)P & ~(InvalidUpper - 1)) { |
| fprintf (stderr, "boundscheck: out of rewrite ptrs: %x %x: %x %x, pc=%x\n", |
| Source, Dest, InvalidLower, invalidptr, (void*)__builtin_return_address(0)); |
| fflush (stderr); |
| return Dest; |
| } |
| |
| adl_splay_insert (&(Pool->OOB), P, 1, Dest); |
| return invalidptr; |
| } |
| |
| /* |
| * Allow pointers to the first page in memory provided that they remain |
| * within that page. Loads and stores using such pointers will fault. This |
| * allows indexing of NULL pointers without error. |
| */ |
| if (Source < (unsigned char *)(4096)) { |
| if (Dest < (unsigned char *)(4096)) { |
| return Dest; |
| } else { |
| if (logregs) |
| fprintf (stderr, "boundscheck : rewrite: %x %x %x %x, pc=%x\n", |
| S, Source, Dest, len, (void*)__builtin_return_address(0)); |
| if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower; |
| ++invalidptr; |
| void* P = invalidptr; |
| if ((unsigned)P & ~(InvalidUpper - 1)) { |
| fprintf (stderr, "boundscheck: out of rewrite ptrs: %x %x: %x %x, pc=%x\n", |
| Source, Dest, InvalidLower, invalidptr, (void*)__builtin_return_address(0)); |
| fflush (stderr); |
| return Dest; |
| } |
| |
| adl_splay_insert (&(Pool->OOB), P, 1, Dest); |
| return invalidptr; |
| } |
| } |
| |
| /* |
| * The node is not found or is not within bounds; fail! |
| */ |
| if (fs) { |
| ReportBoundsCheck ((unsigned)Source, |
| (unsigned)Dest, |
| (unsigned)__builtin_return_address(0), |
| (unsigned)S, |
| (unsigned)len); |
| } else { |
| ReportBoundsCheck ((unsigned)Source, |
| (unsigned)Dest, |
| (unsigned)__builtin_return_address(0), |
| (unsigned)0, |
| (unsigned)0); |
| } |
| fflush (stderr); |
| abort (); |
| return Dest; |
| } |
| |
| int |
| boundscheckui_lookup (PoolTy * Pool, void * Source ) { |
| //search for object for Source in splay tree, return length |
| return adl_splay_lookup (&(Pool->Objects), &Source); |
| } |
| |
| void * |
| boundscheckui_check (int len, PoolTy * Pool, void * Source, void * Dest) { |
| /* |
| * First, attempt to find the pointer within a valid object. If the source |
| * pointer is within a valid object but the destination pointer is not, then |
| * rewrite the pointer. |
| */ |
| void* S = Source; |
| //unsigned len = 0; |
| |
| if (len) { |
| if ((S <= Dest) && (((char*)S + len) > (char*)Dest)) { |
| return Dest; |
| } else { |
| if (logregs) |
| fprintf (stderr, "boundscheckui: rewrite: %x %x %x %x, pc=%x\n", |
| S, Source, Dest, len, (void*)__builtin_return_address(0)); |
| if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower; |
| ++invalidptr; |
| void* P = invalidptr; |
| //if ((unsigned)P & ~(InvalidUpper - 1)) { |
| if ((unsigned) P == InvalidUpper) { |
| fprintf (stderr, "boundscheckui: out of rewrite ptrs: %x %x, pc=%x\n", |
| InvalidLower, InvalidUpper, invalidptr); |
| //Source, Dest, (void*)__builtin_return_address(0)); |
| fflush (stderr); |
| abort(); |
| } |
| adl_splay_insert (&(Pool->OOB), P, 1, Dest); |
| return invalidptr; |
| } |
| } |
| |
| |
| /* |
| * Allow pointers to the first page in memory provided that they remain |
| * within that page. Loads and stores using such pointers will fault. This |
| * allows indexing of NULL pointers without error. |
| */ |
| if (Source < (unsigned char *)(4096)) { |
| if (Dest < (unsigned char *)(4096)) { |
| return Dest; |
| } else { |
| if (logregs) |
| fprintf (stderr, "boundscheckui: rewrite: %x %x %x %x, pc=%x\n", |
| S, Source, Dest, len, (void*)__builtin_return_address(0)); |
| if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower; |
| ++invalidptr; |
| void* P = invalidptr; |
| //if ((unsigned)P & ~(InvalidUpper - 1)) { |
| if ((unsigned) P == InvalidUpper) { |
| fprintf (stderr, "boundscheckui: out of rewrite ptrs: %x %x, pc=%x\n", |
| InvalidLower, InvalidUpper, invalidptr); |
| //Source, Dest, (void*)__builtin_return_address(0)); |
| fflush (stderr); |
| abort(); |
| } |
| adl_splay_insert (&(Pool->OOB), P, 1, Dest); |
| return invalidptr; |
| } |
| } |
| |
| /* |
| * Attempt to look for the object in the external object splay tree. |
| */ |
| S = Source; |
| unsigned len_new = 0; |
| int fs = adl_splay_retrieve (&(ExternalObjects), &S, &len_new, 0); |
| if (fs) { |
| if ((S <= Dest) && (((char*)S + len_new) > (char*)Dest)) { |
| return Dest; |
| } else { |
| ReportBoundsCheck ((unsigned)Source, |
| (unsigned)Dest, |
| (unsigned)__builtin_return_address(0), |
| (unsigned)S, |
| (unsigned)len); |
| } |
| } |
| |
| /* |
| * We cannot find the object. Print a warning and continue execution. |
| */ |
| |
| return Dest; |
| } |
| |
| void * |
| boundscheckui (PoolTy * Pool, void * Source, void * Dest) { |
| // This code is inlined at all boundscheckui calls |
| |
| // Search the splay for Source and return the bounds of the object |
| int len = boundscheckui_lookup (Pool, Source); |
| |
| // Check if destination lies in the same object |
| if (__builtin_expect (len && |
| ((Source <= Dest) && |
| ((char*)Source + len) > (char*)Dest), 1)) { |
| return Dest; |
| } else { |
| // |
| // Valid object not found in splay tree or Dest is not within the valid |
| // object |
| // |
| return boundscheckui_check( len, Pool, Source, Dest ); |
| } |
| } |
| |
| void * |
| rewrite_ptr (void * p) { |
| static void * OOBTree; |
| |
| if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower; |
| ++invalidptr; |
| void* P = invalidptr; |
| //if ((unsigned)P & ~(InvalidUpper - 1)) { |
| if ((unsigned) P == InvalidUpper) { |
| fprintf (stderr, "rewrite: out of rewrite ptrs: %x %x, pc=%x\n", |
| InvalidLower, InvalidUpper, invalidptr); |
| //Source, Dest, (void*)__builtin_return_address(0)); |
| fflush (stderr); |
| abort(); |
| } |
| |
| adl_splay_insert (&(OOBTree), P, 1, p); |
| return invalidptr; |
| } |
| |
| /* |
| * Function: getActualValue() |
| * |
| * Description: |
| * If src is an out of object pointer, get the original value. |
| */ |
| void * |
| pchk_getActualValue (PoolTy * Pool, void * src) { |
| if ((unsigned)src <= InvalidLower) return src; |
| |
| void* tag = 0; |
| |
| /* outside rewrite zone */ |
| if ((unsigned)src & ~(InvalidUpper - 1)) return src; |
| if (adl_splay_retrieve(&(Pool->OOB), &src, 0, &tag)) { |
| return tag; |
| } |
| |
| /* Lookup has failed */ |
| fprintf (stderr, "GetActualValue failure: src = %x, pc = %x", (unsigned) src, |
| (unsigned) __builtin_return_address(0)); |
| fflush (stderr); |
| abort (); |
| return tag; |
| } |
| |
| // Check that Node falls within the pool and within start and (including) |
| // end offset |
| void |
| poolcheckalign (PoolTy *Pool, void *Node, unsigned StartOffset, |
| unsigned EndOffset) { |
| PoolSlab *PS; |
| if (StartOffset >= Pool->NodeSize || EndOffset >= Pool->NodeSize) { |
| printf("Error: Offset specified exceeded node size"); |
| exit(-1); |
| } |
| |
| if (Pool->AllocadPool > 0) { |
| if (Pool->allocaptr <= Node) { |
| unsigned diffPtr = (unsigned)Node - (unsigned)Pool->allocaptr; |
| unsigned offset = diffPtr % Pool->NodeSize; |
| if ((diffPtr < (unsigned)Pool->AllocadPool ) && (offset >= StartOffset) && |
| (offset <= EndOffset)) |
| return; |
| } |
| assert(0 && "poolcheckalign failure FAILING \n"); |
| exit(-1); |
| } |
| |
| PS = (PoolSlab*)((long)Node & ~(PageSize-1)); |
| |
| if (Pool->NumSlabs > AddrArrSize) { |
| hash_set<void*> &theSlabs = *Pool->Slabs; |
| if (theSlabs.find((void*)PS) == theSlabs.end()) { |
| // Check the LargeArrays |
| if (Pool->LargeArrays) { |
| PoolSlab *PSlab = (PoolSlab*) Pool->LargeArrays; |
| int Idx = -1; |
| while (PSlab) { |
| assert(PSlab && "poolcheck: node being free'd not found in " |
| "allocation pool specified!\n"); |
| Idx = PSlab->containsElement(Node, Pool->NodeSize); |
| if (Idx != -1) { |
| Pool->prevPage[Pool->lastUsed] = PS; |
| Pool->lastUsed = (Pool->lastUsed + 1) % 4; |
| break; |
| } |
| PSlab = PSlab->Next; |
| } |
| |
| if (Idx == -1) { |
| fprintf(stderr, "poolcheck1: node being checked not found in pool with right" |
| " alignment\n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } else { |
| //exit(-1); |
| } |
| } else { |
| fprintf(stderr, "poolcheck2: node being checked not found in pool with right" |
| " alignment\n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } |
| } else { |
| unsigned long startaddr = (unsigned long)PS->getElementAddress(0,0); |
| if (startaddr > (unsigned long) Node) { |
| fprintf(stderr, "poolcheck: node being checked points to meta-data \n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } |
| unsigned long offset = ((unsigned long) Node - (unsigned long) startaddr) % Pool->NodeSize; |
| if ((offset < StartOffset) || (offset > EndOffset)) { |
| fprintf(stderr, "poolcheck3: node being checked does not have right alignment\n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } |
| Pool->prevPage[Pool->lastUsed] = PS; |
| Pool->lastUsed = (Pool->lastUsed + 1) % 4; |
| } |
| } else { |
| bool found = false; |
| for (unsigned i = 0; i < AddrArrSize && !found; ++i) { |
| if ((unsigned)Pool->SlabAddressArray[i] == (unsigned) PS) { |
| found = true; |
| Pool->prevPage[Pool->lastUsed] = PS; |
| Pool->lastUsed = (Pool->lastUsed + 1) % 4; |
| } |
| } |
| |
| if (found) { |
| // Check that Node does not point to PoolSlab meta-data |
| unsigned long startaddr = (unsigned long)PS->getElementAddress(0,0); |
| if (startaddr > (unsigned long) Node) { |
| printf("poolcheck: node being checked points to meta-data \n"); |
| exit(-1); |
| } |
| unsigned long offset = ((unsigned long) Node - (unsigned long) startaddr) % Pool->NodeSize; |
| if ((offset < StartOffset) || (offset > EndOffset)) { |
| fprintf(stderr, "poolcheck4: node being checked does not have right alignment\n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } |
| } else { |
| // Check the LargeArrays |
| if (Pool->LargeArrays) { |
| PoolSlab *PSlab = (PoolSlab*) Pool->LargeArrays; |
| int Idx = -1; |
| while (PSlab) { |
| assert(PSlab && "poolcheck: node being free'd not found in " |
| "allocation pool specified!\n"); |
| Idx = PSlab->containsElement(Node, Pool->NodeSize); |
| if (Idx != -1) { |
| Pool->prevPage[Pool->lastUsed] = PS; |
| Pool->lastUsed = (Pool->lastUsed + 1) % 4; |
| break; |
| } |
| PSlab = PSlab->Next; |
| } |
| if (Idx == -1) { |
| fprintf(stderr, "poolcheck6: node being checked not found in pool with right" |
| " alignment\n"); |
| fflush(stderr); |
| abort(); |
| exit(-1); |
| } |
| } else { |
| fprintf(stderr, "poolcheck5: node being checked not found in pool with right" |
| " alignment %x %x\n", (unsigned)Pool, (unsigned)Node); |
| fflush(stderr); |
| abort(); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void |
| poolfree(PoolTy *Pool, void *Node) { |
| assert(Pool && "Null pool pointer passed in to poolfree!\n"); |
| DEBUG(printf("poolfree %x %x \n",Pool,Node);) |
| PoolSlab *PS; |
| int Idx; |
| |
| |
| if (logregs) { |
| printf(" poolfree:1368: poolfree to addr 0x%08x\n", (unsigned)Node); |
| } |
| // update DebugMetaData |
| globalfreeID++; |
| |
| // FIXME: figure what mykey, NumPPAge and len are for |
| void * mykey; |
| unsigned len = 1; |
| unsigned NumPPage = 0; |
| unsigned offset = (unsigned)((long)Node & (PPageSize - 1)); |
| PDebugMetaData debugmetadataptr; |
| mykey = Node; |
| |
| // Retrieve the debug information about the node. This will include a |
| // pointer to the canonical page. |
| adl_splay_retrieve (&(Pool->Objects), &mykey, &len, (void **) &debugmetadataptr); |
| |
| if (logregs) { |
| printf(" poolfree:1387: mykey = 0x%08x offset = 0x%08x\n", (unsigned)mykey, offset); |
| printf(" poolfree:1388: len = %d\n", len); |
| } |
| |
| // figure out how many pages does this object span to |
| // protect the pages. First we sum the offset and len |
| // to get the total size we originally remapped. |
| // Then, we determine if this sum is a multiple of |
| // physical page size. If it is not, then we increment |
| // the number of pages to protect. |
| // FIXME!!! |
| |
| NumPPage = (len / PPageSize) + 1; |
| if ( (len - (NumPPage-1) * PPageSize) > (PPageSize - offset) ) |
| NumPPage++; |
| |
| assert (debugmetadataptr && "poolfree: No debugmetadataptr\n"); |
| globalTemp = debugmetadataptr->canonAddr; |
| |
| if (logregs) { |
| printf(" poolfree:1397: NumPPage = %d\n", NumPPage); |
| printf(" poolfree:1398: canonical address is 0x%x\n", (unsigned)globalTemp); |
| } |
| updatePtrMetaData(debugmetadataptr, globalfreeID, __builtin_return_address(0)); |
| |
| // |
| // Allow the poolcheck runtime to finish the bookkeping it needs to do. |
| // |
| adl_splay_delete (&Pool->Objects, Node); |
| |
| if (1) { // THIS SHOULD BE SET FOR SAFECODE! |
| unsigned TheIndex; |
| PS = SearchForContainingSlab(Pool, globalTemp, TheIndex); |
| Idx = TheIndex; |
| assert (PS && "poolfree: No poolslab found for object!\n"); |
| PS->freeElement(Idx); |
| } else { |
| // Since it is undefined behavior to free a node which has not been |
| // allocated, we know that the pointer coming in has to be a valid node |
| // pointer in the pool. Mask off some bits of the address to find the base |
| // of the pool. |
| assert((PageSize & PageSize-1) == 0 && "Page size is not a power of 2??"); |
| PS = (PoolSlab*)((long)Node & ~(PageSize-1)); |
| |
| if (PS->isSingleArray) { |
| PS->unlinkFromList(); |
| |
| // works done to update the DebugMetaData struct for |
| // dangling pointer runtime |
| globalfreeID++; |
| void * mykey; |
| unsigned len = 0; |
| PDebugMetaData debugmetadataptr; |
| mykey = Node; |
| adl_splay_retrieve(&(Pool->DPTree), &mykey, &len, (void **) &debugmetadataptr); |
| updatePtrMetaData(debugmetadataptr, globalfreeID, __builtin_return_address(0)); |
| return; |
| } |
| |
| Idx = PS->containsElement(Node, Pool->NodeSize); |
| assert((int)Idx != -1 && "Node not contained in slab??"); |
| } |
| |
| // return if PS is NULL |
| if (!PS) |
| return; |
| assert (PS && "PS is NULL!\n"); |
| |
| // If PS was full, it must have been in list #2. Unlink it and move it to |
| // list #1. |
| if (PS->isFull()) { |
| // Now that we found the node, we are about to free an element from it. |
| // This will make the slab no longer completely full, so we must move it to |
| // the other list! |
| PS->unlinkFromList(); // Remove it from the Ptr2 list. |
| |
| // |
| // Do not re-use single array slabs. |
| // |
| if (!(PS->isSingleArray)) { |
| PoolSlab **InsertPosPtr = (PoolSlab**)&Pool->Ptr1; |
| |
| // If the partially full list has an empty node sitting at the front of |
| // the list, insert right after it. |
| if ((*InsertPosPtr)) |
| if ((*InsertPosPtr)->isEmpty()) |
| InsertPosPtr = &(*InsertPosPtr)->Next; |
| |
| PS->addToList(InsertPosPtr); // Insert it now in the Ptr1 list. |
| } |
| } |
| |
| // Ok, if this slab is empty, we unlink it from the of slabs and either move |
| // it to the head of the list, or free it, depending on whether or not there |
| // is already an empty slab at the head of the list. |
| if ((PS->isEmpty()) && (!(PS->isSingleArray))) { |
| PS->unlinkFromList(); // Unlink from the list of slabs... |
| |
| // If we can free this pool, check to see if there are any empty slabs at |
| // the start of this list. If so, delete the FirstSlab! |
| PoolSlab *FirstSlab = (PoolSlab*)Pool->Ptr1; |
| if (0 && FirstSlab && FirstSlab->isEmpty()) { |
| // Here we choose to delete FirstSlab instead of the pool we just freed |
| // from because the pool we just freed from is more likely to be in the |
| // processor cache. |
| FirstSlab->unlinkFromList(); |
| FirstSlab->destroy(); |
| // Pool->Slabs.erase((void *)FirstSlab); |
| } |
| |
| // Link our slab onto the head of the list so that allocations will find it |
| // efficiently. |
| PS->addToList((PoolSlab**)&Pool->Ptr1); |
| } |
| |
| // Protect the shadow pages |
| ProtectShadowPage((void *)((long)Node & ~(PPageSize - 1)), NumPPage); |
| |
| // |
| // An object has been freed. Set up a signal handler to catch any dangling |
| // pointer references. |
| // |
| // FIXME: |
| // This code was placed here because it does not appear to work when placed |
| // in poolinit(). |
| // |
| struct sigaction sa; |
| bzero (&sa, sizeof (struct sigaction)); |
| sa.sa_sigaction = bus_error_handler; |
| sa.sa_flags = SA_SIGINFO; |
| if (sigaction(SIGBUS, &sa, NULL) == -1) { |
| fprintf (stderr, "sigaction installer failed!"); |
| fflush (stderr); |
| } |
| |
| return; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // Dangling pointer runtime functions |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // |
| // Function: createPtrMetaData() |
| // Allocates memory for a DebugMetaData struct and fills up the appropriate |
| // fields so to keep a record of the pointer's meta data |
| // |
| extern "C" { void * internal_malloc (unsigned int size);} |
| static PDebugMetaData |
| createPtrMetaData (unsigned paramAllocID, |
| unsigned paramFreeID, |
| void * paramAllocPC, |
| void * paramFreePC, |
| void * paramCanon) { |
| // FIXME: |
| // This only works because DebugMetaData and a splay tree node are of |
| // identical size. |
| PDebugMetaData ret = (PDebugMetaData) internal_malloc(sizeof(DebugMetaData)); |
| ret->allocID = paramAllocID; |
| ret->freeID = paramFreeID; |
| ret->allocPC = paramAllocPC; |
| ret->freePC = paramFreePC; |
| ret->canonAddr = paramCanon; |
| |
| return ret; |
| } |
| |
| static inline void |
| updatePtrMetaData (PDebugMetaData debugmetadataptr, |
| unsigned globalfreeID, |
| void * paramFreePC) { |
| debugmetadataptr->freeID = globalfreeID; |
| debugmetadataptr->freePC = paramFreePC; |
| return; |
| } |
| |
| // |
| // Function: bus_error_handler() |
| // |
| // Description: |
| // This is the signal handler that catches bad memory references. |
| // |
| static void |
| bus_error_handler (int sig, siginfo_t * info, void * context) { |
| signal(SIGBUS, NULL); |
| ucontext_t * mycontext = (ucontext_t *) context; |
| |
| unsigned len = 0; |
| void * faultAddr = info->si_addr; |
| PDebugMetaData debugmetadataptr; |
| int fs = 0; |
| if (0 == (fs = adl_splay_retrieve(&(dummyPool.DPTree), &faultAddr, &len, (void **) &debugmetadataptr))) |
| { |
| fprintf(stderr, "signal handler: retrieving debug meta data failed"); |
| fflush(stderr); |
| abort(); |
| } |
| |
| // FIXME: Correct the semantics for calculating NumPPage |
| unsigned NumPPage; |
| unsigned offset = (unsigned) ((long)info->si_addr & (PPageSize - 1) ); |
| NumPPage = (len / PPageSize) + 1; |
| if ( (len - (NumPPage-1) * PPageSize) > (PPageSize - offset) ) |
| NumPPage++; |
| |
| // This is necessary so that the program continues execution, |
| // especially in debugging mode |
| UnprotectShadowPage((void *)((long)info->si_addr & ~(PPageSize - 1)), NumPPage); |
| |
| //void* S = info->si_addr; |
| // printing reports |
| void * address = 0; |
| unsigned program_counter = 0; |
| unsigned alloc_pc = 0; |
| unsigned free_pc = 0; |
| unsigned allocID = 0; |
| unsigned freeID = 0; |
| |
| #if defined(__APPLE__) |
| #if defined(i386) || defined(__i386__) || defined(__x86__) |
| program_counter = mycontext->uc_mcontext->__ss.__eip; |
| #endif |
| alloc_pc = ((unsigned) (debugmetadataptr->allocPC)) - 5; |
| free_pc = ((unsigned) (debugmetadataptr->freePC)) - 5; |
| allocID = debugmetadataptr->allocID; |
| freeID = debugmetadataptr->freeID; |
| #endif |
| |
| ReportDanglingPointer (address, program_counter, |
| alloc_pc, allocID, |
| free_pc, freeID); |
| |
| // reinstall the signal handler for subsequent faults |
| struct sigaction sa; |
| sa.sa_sigaction = bus_error_handler; |
| sa.sa_flags = SA_SIGINFO; |
| if (sigaction(SIGBUS, &sa, NULL) == -1) |
| printf("sigaction installer failed!"); |
| |
| return; |
| } |
| |
| |
| |
| // |
| // Function: funccheck() |
| // |
| // Description: |
| // Determine whether the specified function pointer is one of the functions |
| // in the given list. |
| // |
| // Inputs: |
| // num - The number of function targets in the DSNode. |
| // f - The function pointer that we are testing. |
| // g - The first function given in the DSNode. |
| // |
| void |
| funccheck (unsigned num, void *f, void *g, ...) { |
| va_list ap; |
| unsigned i = 0; |
| |
| // Test against the first function in the list |
| if (f == g) return; |
| i++; |
| va_start(ap, g); |
| for ( ; i != num; ++i) { |
| void *h = va_arg(ap, void *); |
| if (f == h) { |
| return; |
| } |
| } |
| if (logregs) { |
| fprintf(stderr, "funccheck failed(num=%d): %x %x\n", num, f, g); |
| fflush(stderr); |
| } |
| abort(); |
| } |
| |
| void |
| poolstats() { |
| fprintf (stderr, "pool mem usage %d\n", poolmemusage); |
| fflush (stderr); |
| } |