1/* 2 Title: Validate addresses in objects. 3 4 Copyright (c) 2006, 2012, 2017 5 David C.J. Matthews 6 7 This library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 This library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with this library; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 21*/ 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#elif defined(_WIN32) 25#include "winconfig.h" 26#else 27#error "No configuration file" 28#endif 29 30#ifdef HAVE_ASSERT_H 31#include <assert.h> 32#define ASSERT(x) assert(x) 33#else 34#define ASSERT(x) 35#endif 36 37 38#include "globals.h" 39#include "diagnostics.h" 40#include "machine_dep.h" 41#include "scanaddrs.h" 42#include "memmgr.h" 43 44#define INRANGE(val,start,end)\ 45 (start <= val && val < end) 46 47static void CheckAddress(PolyWord *pt) 48{ 49 MemSpace *space = gMem.SpaceForAddress(pt-1); 50 if (space == 0) 51 { 52 Log("Check: Bad pointer %p (no space found)\n", pt); 53 ASSERT(space != 0); 54 } 55 if (space->spaceType == ST_STACK) // This may not have valid length words. 56 return; 57 PolyObject *obj = (PolyObject*)pt; 58 ASSERT(obj->ContainsNormalLengthWord()); 59 POLYUNSIGNED length = obj->Length(); 60 if (pt+length > space->top) 61 { 62 Log("Check: Bad pointer %p (space %p) length %" POLYUFMT "\n", pt, space, length); 63 ASSERT(pt+length <= space->top); 64 } 65 if (space->spaceType == ST_LOCAL) 66 { 67 LocalMemSpace *lSpace = (LocalMemSpace*)space; 68 if (!((pt > lSpace->bottom && pt+length <= lSpace->lowerAllocPtr) || 69 (pt > lSpace->upperAllocPtr && pt+length <= space->top))) 70 { 71 Log("Check: Bad pointer %p (space %p) length %" POLYUFMT " outside allocated area\n", pt, space, length); 72 ASSERT((pt > lSpace->bottom && pt+length <= lSpace->lowerAllocPtr) || 73 (pt > lSpace->upperAllocPtr && pt+length <= space->top)); 74 } 75 } 76} 77 78void DoCheck (const PolyWord pt) 79{ 80 if (pt == PolyWord::FromUnsigned(0)) return; 81 82 if (pt.IsTagged()) return; 83 84 CheckAddress(pt.AsStackAddr()); 85} 86 87class ScanCheckAddress: public ScanAddress 88{ 89public: 90 virtual PolyObject *ScanObjectAddress(PolyObject *pt) { CheckAddress((PolyWord*)pt); return pt; } 91}; 92 93void DoCheckObject (const PolyObject *base, POLYUNSIGNED L) 94{ 95 96 PolyWord *pt = (PolyWord*)base; 97 CheckAddress(pt); 98 MemSpace *space = gMem.SpaceForAddress(pt-1); 99 if (space == 0) 100 Crash ("Bad pointer 0x%08" PRIxPTR " found", (uintptr_t)pt); 101 102 ASSERT (OBJ_IS_LENGTH(L)); 103 104 POLYUNSIGNED n = OBJ_OBJECT_LENGTH(L); 105 if (n == 0) return; 106 107 ASSERT (n > 0); 108 ASSERT(pt-1 >= space->bottom && pt+n <= space->top); 109 110 byte flags = GetTypeBits(L); /* discards GC flag and mutable bit */ 111 112 if (flags == F_BYTE_OBJ) /* possibly signed byte object */ 113 return; /* Nothing more to do */ 114 115 if (flags == F_CODE_OBJ) /* code object */ 116 { 117 ScanCheckAddress checkAddr; 118 /* We flush the instruction cache here in case we change any of the 119 instructions when we update addresses. */ 120 machineDependent->FlushInstructionCache(pt, (n + 1) * sizeof(PolyWord)); 121 machineDependent->ScanConstantsWithinCode((PolyObject *)base, (PolyObject *)base, n, &checkAddr); 122 /* Skip to the constants. */ 123 base->GetConstSegmentForCode(n, pt, n); 124 } 125 else if (flags == F_CLOSURE_OBJ) 126 { 127 n -= sizeof(PolyObject*) / sizeof(PolyWord); 128 pt += sizeof(PolyObject*) / sizeof(PolyWord); 129 } 130 else ASSERT (flags == 0); /* ordinary word object */ 131 132 while (n--) DoCheck (*pt++); 133} 134 135void DoCheckPointer (const PolyWord pt) 136{ 137 if (pt == PolyWord::FromUnsigned(0)) return; 138 139 if (OBJ_IS_AN_INTEGER(pt)) return; 140 141 DoCheck (pt); 142 143 if (pt.IsDataPtr()) 144 { 145 PolyObject *obj = pt.AsObjPtr(); 146 DoCheckObject (obj, obj->LengthWord()); 147 } 148} 149 150// Check all the objects in the memory. Used to check the garbage collector 151// 152void DoCheckMemory() 153{ 154 ScanCheckAddress memCheck; 155 // Scan the local areas. 156 for (std::vector<LocalMemSpace*>::iterator i = gMem.lSpaces.begin(); i < gMem.lSpaces.end(); i++) 157 { 158 LocalMemSpace *space = *i; 159 memCheck.ScanAddressesInRegion(space->bottom, space->lowerAllocPtr); 160 memCheck.ScanAddressesInRegion(space->upperAllocPtr, space->top); 161 } 162 // Scan the permanent mutable areas. 163 for (std::vector<PermanentMemSpace*>::iterator i = gMem.pSpaces.begin(); i < gMem.pSpaces.end(); i++) 164 { 165 PermanentMemSpace *space = *i; 166 if (space->isMutable && ! space->byteOnly) 167 memCheck.ScanAddressesInRegion(space->bottom, space->top); 168 } 169} 170