Path: blob/master/runtime/gc_check/CheckEngine.cpp
5985 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122/**23* @file24* @ingroup GC_CheckEngine25*/2627#include "j9.h"28#include "j9cfg.h"29#include "HeapIteratorAPI.h"30#include "mmhook_internal.h"3132#include "VMHelpers.hpp"3334#if !defined(UT_TRACE_OVERHEAD)35#define UT_TRACE_OVERHEAD -1 /* disable assertions and tracepoints since we're not in the GC module proper */36#endif3738#include "ArrayletLeafIterator.hpp"39#include "CheckEngine.hpp"40#include "Base.hpp"41#include "CheckBase.hpp"42#include "CheckCycle.hpp"43#include "CheckError.hpp"44#include "CheckReporter.hpp"45#include "CheckReporterTTY.hpp"46#include "ClassModel.hpp"47#include "ForwardedHeader.hpp"48#include "GCExtensions.hpp"49#include "HeapRegionDescriptor.hpp"50#include "ModronTypes.hpp"51#include "ObjectModel.hpp"52#include "ObjectAccessBarrier.hpp"53#include "ScanFormatter.hpp"54#include "SublistPool.hpp"55#include "SublistPuddle.hpp"5657/**58* Private struct used as the user data for object slot iterator callbacks.59*/60typedef struct ObjectSlotIteratorCallbackUserData {61GC_CheckEngine* engine; /* Input */62J9MM_IterateRegionDescriptor* regionDesc; /* Input */63UDATA result; /* Output */64} ObjectSlotIteratorCallbackUserData;6566static jvmtiIterationControl check_objectSlotsCallback(J9JavaVM *javaVM, J9MM_IterateObjectDescriptor *objectDesc, J9MM_IterateObjectRefDescriptor *refDesc, void *userData);67static bool isPointerInRegion(void *pointer, J9MM_IterateRegionDescriptor *regionDesc);6869/*70* Define alignment masks for J9Objects:71*72* o On 64 bit all objects are 8 byte aligned73* o On 31/32 bit:74* - Objects allocated on stack are 4 bytes aligned75* - Objects allocated on heap are either 4 or 8 byte aligned dependent76* on platform77*/78#define J9MODRON_GCCHK_J9CLASS_ALIGNMENT_MASK 0xFF7980#if defined(J9VM_ENV_DATA64)81#define J9MODRON_GCCHK_ONSTACK_ALIGNMENT_MASK 0x782#else /* J9VM_ENV_DATA64 */83#define J9MODRON_GCCHK_ONSTACK_ALIGNMENT_MASK 0x384#endif /* J9VM_ENV_DATA64*/8586#define J9MODRON_GCCHK_J9CLASS_EYECATCHER (UDATA)0x996699668788/**89* Clear the counts of OwnableSynchronizerObjects90*/91void92GC_CheckEngine::clearCountsForOwnableSynchronizerObjects()93{94_ownableSynchronizerObjectCountOnList = UNINITIALIZED_SIZE_FOR_OWNABLESYNCHRONIER;95_ownableSynchronizerObjectCountOnHeap = UNINITIALIZED_SIZE_FOR_OWNABLESYNCHRONIER;96}9798/**99*100*/101bool102GC_CheckEngine::verifyOwnableSynchronizerObjectCounts()103{104bool ret = true;105106if ((UNINITIALIZED_SIZE_FOR_OWNABLESYNCHRONIER != _ownableSynchronizerObjectCountOnList) && (UNINITIALIZED_SIZE_FOR_OWNABLESYNCHRONIER != _ownableSynchronizerObjectCountOnHeap)) {107if (_ownableSynchronizerObjectCountOnList != _ownableSynchronizerObjectCountOnHeap) {108PORT_ACCESS_FROM_PORT(_portLibrary);109j9tty_printf(PORTLIB, " <gc check: found count=%zu of OwnableSynchronizerObjects on Heap doesn't match count=%zu on lists>\n", _ownableSynchronizerObjectCountOnHeap, _ownableSynchronizerObjectCountOnList);110ret = false;111}112}113114return ret;115}116117118/**119* Clear the cache of previously visited objects.120*/121void122GC_CheckEngine::clearPreviousObjects()123{124_lastHeapObject1.type = GC_CheckElement::type_none;125_lastHeapObject2.type = GC_CheckElement::type_none;126_lastHeapObject3.type = GC_CheckElement::type_none;127}128129/**130* Push an object onto the list of previously visited objects131* (and drop oldest object).132*/133void134GC_CheckEngine::pushPreviousObject(J9Object *objectPtr)135{136_lastHeapObject3 = _lastHeapObject2;137_lastHeapObject2 = _lastHeapObject1;138139_lastHeapObject1.type = GC_CheckElement::type_object;140_lastHeapObject1.u.object = objectPtr;141}142143/**144* Push a class onto the list of previously visited objects145* (and drop oldest object).146*/147void148GC_CheckEngine::pushPreviousClass(J9Class* clazz)149{150_lastHeapObject3 = _lastHeapObject2;151_lastHeapObject2 = _lastHeapObject1;152153_lastHeapObject1.type = GC_CheckElement::type_class;154_lastHeapObject1.u.clazz = clazz;155}156157158/**159* Determine whether or not the given object is contained in the given segment160*161* @return true if objectPtr is contained in the given segment162* @return false otherwise163*/164bool165GC_CheckEngine::isPointerInSegment(void *pointer, J9MemorySegment *segment)166{167return ( ((UDATA)pointer >= (UDATA)segment->heapBase) && ((UDATA)pointer < (UDATA)segment->heapAlloc) );168}169170/**171* Determine whether or not the given object is contained in the given stack172*173* @return true if objectPtr is contained in the given stack174* @return false otherwise175*/176bool177GC_CheckEngine::isObjectOnStack(J9Object *objectPtr, J9JavaStack *stack)178{179return ((UDATA)objectPtr < (UDATA)stack->end) && ((UDATA)objectPtr >= (UDATA)(stack+1));180}181182/**183* Find the class segment which contains a given class.184*185* @param clazz Pointer to the class to search for186*187* @return the segment which contains the class, or188* NULL if the class was not found in any of the class segments189*/190J9MemorySegment*191GC_CheckEngine::findSegmentForClass(J9JavaVM *javaVM, J9Class *clazz)192{193J9MemorySegmentList * segmentList = javaVM->classMemorySegments;194J9MemorySegment * segment = (J9MemorySegment *) avl_search(&segmentList->avlTreeData, (UDATA)clazz);195if (NULL != segment) {196UDATA flags = MEMORY_TYPE_RAM_CLASS | MEMORY_TYPE_UNDEAD_CLASS;197if (0 != (segment->type & flags)) {198return segment;199}200}201return NULL;202}203204/**205* Find the region which contains a given object. Return true and write to regionDescOutput if206* the region is found, return false otherwise.207*/208bool209GC_CheckEngine::findRegionForPointer(J9JavaVM* javaVM, void *pointer, J9MM_IterateRegionDescriptor* regionDescOutput)210{211bool found = false;212213/* Check the local cache of the previously found region */214if (isPointerInRegion(pointer, &_regionDesc)) {215copyRegionDescription(&_regionDesc, regionDescOutput);216found = true;217} else if (0 != javaVM->memoryManagerFunctions->j9mm_find_region_for_pointer(javaVM, pointer, regionDescOutput)) {218/* If a region is found cache it in _regionDesc for the next lookup */219copyRegionDescription(regionDescOutput, &_regionDesc);220found = true;221}222223return found;224}225226/**227* Perform basic verification on an object pointer.228* Checks a pointer for alignment, and optionally searches memory segments for229* this pointer.230*231* @param objectPtr[in] Pointer to the object to be verified232* @param newObjectPtr[out] On return, contains the actual object pointer once forwarding pointers have been followed233* @param regionDesc[out] A pointer to a region structure describing the region of objectPtr. The region will be234* searched for, and the result stored back to the location pointed to by regionDesc235*236* @note regionDesc must not be NULL237* @see @ref findRegionForPointer238*239* @return @ref GCCheckWalkStageErrorCodes240*/241UDATA242GC_CheckEngine::checkJ9ObjectPointer(J9JavaVM *javaVM, J9Object *objectPtr, J9Object **newObjectPtr, J9MM_IterateRegionDescriptor *regionDesc)243{244MM_GCExtensionsBase* extensions = MM_GCExtensions::getExtensions(_javaVM);245assume0(regionDesc != NULL);246247*newObjectPtr = objectPtr;248249if (NULL == objectPtr) {250return J9MODRON_GCCHK_RC_OK;251}252253bool foundRegion = findRegionForPointer(javaVM, objectPtr, regionDesc);254if (!foundRegion) {255/* Is the object on the stack? */256J9VMThread *vmThread;257GC_VMThreadListIterator threadListIterator(javaVM);258while ((vmThread = threadListIterator.nextVMThread()) != NULL) {259if (isObjectOnStack(objectPtr, vmThread->stackObject)) {260return J9MODRON_GCCHK_RC_STACK_OBJECT;261}262}263264if (J9MODRON_GCCHK_J9CLASS_EYECATCHER == J9GC_J9OBJECT_CLAZZ_WITH_FLAGS_VM(objectPtr, javaVM)) {265return J9MODRON_GCCHK_RC_OBJECT_SLOT_POINTS_TO_J9CLASS;266}267268return J9MODRON_GCCHK_RC_NOT_FOUND;269}270271if (0 == regionDesc->objectAlignment) {272/* this is a heap region, but it's not intended for objects (could be free or an arraylet leaf) */273return J9MODRON_GCCHK_RC_NOT_IN_OBJECT_REGION;274}275276/* Now we know object is not on stack we can check that it's correctly aligned277* for a J9Object.278*/279if ((UDATA)(objectPtr) & (regionDesc->objectAlignment - 1)) {280return J9MODRON_GCCHK_RC_UNALIGNED;281}282283if (_cycle->getMiscFlags() & J9MODRON_GCCHK_MISC_MIDSCAVENGE) {284UDATA regionType = ((MM_HeapRegionDescriptor*)regionDesc->id)->getTypeFlags();285if ((regionType & MEMORY_TYPE_NEW) || extensions->isVLHGC()) {286// TODO: ideally, we should only check this in the evacuate segment287// TODO: do some safety checks first -- is there enough room in the segment?288MM_ForwardedHeader forwardedHeader(objectPtr, extensions->compressObjectReferences());289if (forwardedHeader.isForwardedPointer()) {290*newObjectPtr = forwardedHeader.getForwardedObject();291292if (_cycle->getMiscFlags() & J9MODRON_GCCHK_VERBOSE) {293PORT_ACCESS_FROM_PORT(_portLibrary);294j9tty_printf(PORTLIB, " <gc check: found forwarded pointer %p -> %p>\n", objectPtr, *newObjectPtr);295}296297objectPtr = *newObjectPtr;298if (!findRegionForPointer(javaVM, objectPtr, regionDesc)) {299return J9MODRON_GCCHK_RC_NOT_FOUND;300}301302if (0 == regionDesc->objectAlignment) {303/* this is a heap region, but it's not intended for objects (could be free or an arraylet leaf) */304return J9MODRON_GCCHK_RC_NOT_IN_OBJECT_REGION;305}306307/* make sure the forwarded pointer is also aligned */308if ((UDATA)(objectPtr) & (regionDesc->objectAlignment - 1)) {309return J9MODRON_GCCHK_RC_UNALIGNED;310}311}312}313}314315/* Check that elements of a double array are aligned on an 8-byte boundary. For continuous316* arrays, verifying that the J9Indexable object is aligned on an 8-byte boundary is sufficient.317* For arraylets, depending on the layout, elements of the array may be stored on arraylet leafs318* or on the spine. Arraylet leafs should always be aligned on 8-byte boundaries. Checking both319* the first and last element will ensure that we are always checking that elements are aligned320* on the spine.321* */322if (extensions->objectModel.isDoubleArray(objectPtr)) {323j9array_t array = (j9array_t)objectPtr;324UDATA size = extensions->indexableObjectModel.getSizeInElements(array);325U_64* elementPtr = NULL;326327if (0 != size) {328J9VMThread *vmThread = javaVM->internalVMFunctions->currentVMThread(javaVM);329elementPtr = J9JAVAARRAY_EA(vmThread, array, 0, U_64);330if ((UDATA)elementPtr & (sizeof(U_64)-1)) {331return J9MODRON_GCCHK_RC_DOUBLE_ARRAY_UNALIGNED;332}333334elementPtr = J9JAVAARRAY_EA(vmThread, array, size-1, U_64);335if ((UDATA)elementPtr & (sizeof(U_64)-1)) {336return J9MODRON_GCCHK_RC_DOUBLE_ARRAY_UNALIGNED;337}338}339}340341/* TODO: shouldn't the segment be checked for the objectPtr if segment was not NULL? */342return J9MODRON_GCCHK_RC_OK;343}344345/**346* Perform basic verification on a class pointer.347* Calls @ref checkPointer to perform the most basic checks (alignment, is348* contained in a class segment), then performs some checks specific to a349* class pointer.350*351* @param clazz Pointer to the class352* @param allowUndead true if undead classes are allowed in this context353*354* @return @ref GCCheckWalkStageErrorCodes355* @see @ref checkFlags356* @see @ref findSegmentForClass357*/358UDATA359GC_CheckEngine::checkJ9ClassPointer(J9JavaVM *javaVM, J9Class *clazz, bool allowUndead )360{361/* Short circuit if we've recently checked this class.362* In JLTF, this cache is about 94% effective (when its size is 19).363*/364UDATA cacheIndex = ((UDATA)clazz) % CLASS_CACHE_SIZE;365if (allowUndead && (_checkedClassCacheAllowUndead[cacheIndex] == clazz)) {366return J9MODRON_GCCHK_RC_OK;367} else if (_checkedClassCache[cacheIndex] == clazz) {368return J9MODRON_GCCHK_RC_OK;369}370371/* Verify class ptr in known segment.372* As it's a J9Class ptr we only search class segments373*/374if (NULL == clazz) {375return J9MODRON_GCCHK_RC_NULL_CLASS_POINTER;376}377378if ((UDATA)(clazz) & J9MODRON_GCCHK_J9CLASS_ALIGNMENT_MASK) {379return J9MODRON_GCCHK_RC_CLASS_POINTER_UNALIGNED;380}381382J9MemorySegment *segment = findSegmentForClass(javaVM, clazz);383if (segment == NULL) {384return J9MODRON_GCCHK_RC_CLASS_NOT_FOUND;385} else if (!allowUndead && (0 != (segment->type & MEMORY_TYPE_UNDEAD_CLASS))) {386return J9MODRON_GCCHK_RC_CLASS_IS_UNDEAD;387}388389/* Check to ensure J9Class header has the correct eyecatcher.390*/391UDATA result = checkJ9ClassHeader(javaVM, clazz);392if ( J9MODRON_GCCHK_RC_OK != result) {393return result;394}395396/* Check that class is not unloaded */397result = checkJ9ClassIsNotUnloaded(javaVM, clazz);398if ( J9MODRON_GCCHK_RC_OK != result) {399return result;400}401402if (_cycle->getCheckFlags() & J9MODRON_GCCHK_VERIFY_RANGE) {403UDATA delta = (UDATA)segment->heapAlloc - (UDATA)clazz;404405/* Basic check that there is enough room for the class header */406if (delta < sizeof(J9Class)) {407return J9MODRON_GCCHK_RC_CLASS_INVALID_RANGE;408}409}410411/* class checked out. Record it in the cache so we don't need to check it again. */412if (allowUndead) {413_checkedClassCacheAllowUndead[cacheIndex] = clazz;414} else {415_checkedClassCache[cacheIndex] = clazz;416}417418return J9MODRON_GCCHK_RC_OK;419}420421/**422* Verify the integrity of an object on the heap.423* Checks various aspects of object integrity based on the checkFlags.424*425* @param objectPtr Pointer to the object426* @param segment The segment containing the pointer427* @param checkFlags Type/level of verification428*429* @return @ref GCCheckWalkStageErrorCodes430*431* @see @ref checkFlags432*/433UDATA434GC_CheckEngine::checkJ9Object(J9JavaVM *javaVM, J9Object* objectPtr, J9MM_IterateRegionDescriptor *regionDesc, UDATA checkFlags)435{436MM_GCExtensions * extensions = MM_GCExtensions::getExtensions(javaVM);437438assume0(NULL != regionDesc);439440if (NULL == objectPtr) {441return J9MODRON_GCCHK_RC_OK;442}443444if (0 == regionDesc->objectAlignment) {445/* this is a heap region, but it's not intended for objects (could be free or an arraylet leaf) */446return J9MODRON_GCCHK_RC_NOT_IN_OBJECT_REGION;447}448449if (((UDATA)objectPtr) & (regionDesc->objectAlignment - 1)) {450return J9MODRON_GCCHK_RC_UNALIGNED;451}452453if (checkFlags & J9MODRON_GCCHK_VERIFY_CLASS_SLOT) {454/* Check that the class pointer points to the class heap, etc. */455UDATA ret = checkJ9ClassPointer(javaVM, J9GC_J9OBJECT_CLAZZ_VM(objectPtr, javaVM), true);456457if (J9MODRON_GCCHK_RC_OK != ret) {458return ret;459}460}461462#if defined(J9VM_ENV_DATA64)463if (OMR_ARE_ANY_BITS_SET(_cycle->getMiscFlags(), J9MODRON_GCCHK_VALID_INDEXABLE_DATA_ADDRESS) && extensions->objectModel.isIndexable(objectPtr)) {464/* Check that the indexable object has the correct data address pointer */465if (!extensions->indexableObjectModel.isCorrectDataAddr((J9IndexableObject*)objectPtr)) {466return J9MODRON_GCCHK_RC_INVALID_INDEXABLE_DATA_ADDRESS;467}468}469#endif /* (J9VM_ENV_DATA64) */470471if (checkFlags & J9MODRON_GCCHK_VERIFY_RANGE) {472UDATA regionEnd = ((UDATA)regionDesc->regionStart) + regionDesc->regionSize;473UDATA delta = regionEnd - (UDATA)objectPtr;474J9MM_IterateObjectDescriptor objectDesc;475476/* Basic check that there is enough room for the object header */477if (delta < J9JAVAVM_OBJECT_HEADER_SIZE(javaVM)) {478return J9MODRON_GCCHK_RC_INVALID_RANGE;479}480481/* TODO: find out what the indexable header size should really be */482if (extensions->objectModel.isIndexable(objectPtr) && (delta < J9JAVAVM_CONTIGUOUS_HEADER_SIZE(javaVM))) {483return J9MODRON_GCCHK_RC_INVALID_RANGE;484}485486javaVM->memoryManagerFunctions->j9mm_initialize_object_descriptor(javaVM, &objectDesc, objectPtr);487488if (delta < objectDesc.size) {489return J9MODRON_GCCHK_RC_INVALID_RANGE;490}491}492493if (checkFlags & J9MODRON_GCCHK_VERIFY_FLAGS) {494if (!extensions->objectModel.checkIndexableFlag(objectPtr)) {495return J9MODRON_GCCHK_RC_INVALID_FLAGS;496}497498if (extensions->isStandardGC()) {499#if defined(J9VM_GC_GENERATIONAL)500UDATA regionType = ((MM_HeapRegionDescriptor*)regionDesc->id)->getTypeFlags();501if (regionType & MEMORY_TYPE_OLD) {502/* All objects in an old segment must have old bit set */503if (!extensions->isOld(objectPtr)) {504return J9MODRON_GCCHK_RC_OLD_SEGMENT_INVALID_FLAGS;505}506} else {507if (regionType & MEMORY_TYPE_NEW) {508/* Object in a new segment can't have old bit or remembered bit set */509if (extensions->isOld(objectPtr)) {510return J9MODRON_GCCHK_RC_NEW_SEGMENT_INVALID_FLAGS;511}512}513}514#endif /* J9VM_GC_GENERATIONAL */515}516}517518return J9MODRON_GCCHK_RC_OK;519}520521/**522* Verify the integrity of an J9Class object.523* Checks various aspects of object integrity based on the checkFlags.524*525* @param clazzPtr Pointer to the J9Class object526* @param segment The segment containing the pointer527* @param checkFlags Type/level of verification528*529* @return @ref GCCheckWalkStageErrorCodes530*531* @see @ref checkFlags532*/533UDATA534GC_CheckEngine::checkJ9Class(J9JavaVM *javaVM, J9Class *clazzPtr, J9MemorySegment *segment, UDATA checkFlags)535{536if (NULL == clazzPtr) {537return J9MODRON_GCCHK_RC_OK;538}539540if (((UDATA)clazzPtr) & J9MODRON_GCCHK_J9CLASS_ALIGNMENT_MASK) {541return J9MODRON_GCCHK_RC_CLASS_POINTER_UNALIGNED;542}543544/* Check that the class header contains the expected values */545UDATA ret = checkJ9ClassHeader(javaVM, clazzPtr);546if (J9MODRON_GCCHK_RC_OK != ret) {547return ret;548}549550/* Check that class is not unloaded */551ret = checkJ9ClassIsNotUnloaded(javaVM, clazzPtr);552if (J9MODRON_GCCHK_RC_OK != ret) {553return ret;554}555556if (checkFlags & J9MODRON_GCCHK_VERIFY_RANGE) {557UDATA delta = (UDATA)segment->heapAlloc - (UDATA)clazzPtr;558559/* Basic check that there is enough room for the object header */560if (delta < sizeof(J9Class)) {561return J9MODRON_GCCHK_RC_CLASS_INVALID_RANGE;562}563}564565return J9MODRON_GCCHK_RC_OK;566}567568/**569* Verify J9Class header.570* Checks various aspects of object integrity based on the checkFlags.571*572* @param clazz Pointer to the J9Class object573*574* @return @ref GCCheckWalkStageErrorCodes575*/576UDATA577GC_CheckEngine::checkJ9ClassHeader(J9JavaVM *javaVM, J9Class *clazz)578{579/* Check to ensure J9Class header has the correct eyecatcher.580*/581if (clazz->eyecatcher != J9MODRON_GCCHK_J9CLASS_EYECATCHER) {582return J9MODRON_GCCHK_RC_J9CLASS_HEADER_INVALID;583}584return J9MODRON_GCCHK_RC_OK;585}586587/**588* Verify J9Class is not unloaded.589*590* @param clazz Pointer to the J9Class object591*592* @return @ref GCCheckWalkStageErrorCodes593*/594UDATA595GC_CheckEngine::checkJ9ClassIsNotUnloaded(J9JavaVM *javaVM, J9Class *clazz)596{597/* Check to ensure J9Class header has the correct eyecatcher.598*/599if (0 != (clazz->classDepthAndFlags & J9AccClassDying)) {600return J9MODRON_GCCHK_RC_CLASS_IS_UNLOADED;601}602return J9MODRON_GCCHK_RC_OK;603}604605/**606* Verify a stack object.607* Checks various aspects of object integrity based on the checkFlags.608*609* @param objectPtr Pointer to the object610* @param checkFlags Type/level of verification611*612* @return @ref GCCheckWalkStageErrorCodes613* @see @ref checkFlags614*615* @todo Fix checks for flags that are automatically set by the JIT616*/617UDATA618GC_CheckEngine::checkStackObject(J9JavaVM *javaVM, J9Object *objectPtr)619{620MM_GCExtensionsBase * extensions = MM_GCExtensions::getExtensions(javaVM);621622if (NULL == objectPtr) {623return J9MODRON_GCCHK_RC_OK;624}625626if ((UDATA)(objectPtr) & J9MODRON_GCCHK_ONSTACK_ALIGNMENT_MASK) {627return J9MODRON_GCCHK_RC_UNALIGNED;628}629630if (_cycle->getCheckFlags() & J9MODRON_GCCHK_VERIFY_CLASS_SLOT) {631/* Check that the class pointer points to the class heap, etc. */632UDATA ret = checkJ9ClassPointer(javaVM, J9GC_J9OBJECT_CLAZZ_VM(objectPtr, javaVM));633if (J9MODRON_GCCHK_RC_OK != ret) {634return ret;635}636}637638if (_cycle->getCheckFlags() & J9MODRON_GCCHK_VERIFY_FLAGS) {639640if (!extensions->objectModel.checkIndexableFlag(objectPtr)) {641return J9MODRON_GCCHK_RC_INVALID_FLAGS;642}643}644645return J9MODRON_GCCHK_RC_OK;646}647648/**649* Verify an object pointer.650* Verify that the given pointer appears to be a valid heap pointer, and651* if so, proceed to verify the object that it points to.652* Calls checkJ9Object which does the actual checking.653*654* @param javaVM the J9JavaVM struct655* @param objectPtr the object to check656* @return @ref GCCheckWalkStageErrorCodes657*/658UDATA659GC_CheckEngine::checkObjectIndirect(J9JavaVM *javaVM, J9Object *objectPtr)660{661if (NULL == objectPtr) {662return J9MODRON_GCCHK_RC_OK;663}664665/* Short circuit if we've recently checked this object.666* In JLTF, this cache is about 28% effective (size 19), 38% effective (size 61), or 49% effective (size 1021).667*/668UDATA cacheIndex = ((UDATA)objectPtr) % OBJECT_CACHE_SIZE;669if (_checkedObjectCache[cacheIndex] == objectPtr) {670return J9MODRON_GCCHK_RC_OK;671}672673/* Check if reference to J9Object */674J9Object *newObjectPtr = NULL;675J9MM_IterateRegionDescriptor objectRegion; /* initialized by checkJ9ObjectPointer */676UDATA result = checkJ9ObjectPointer(javaVM, objectPtr, &newObjectPtr, &objectRegion);677678if (J9MODRON_GCCHK_RC_OK == result) {679result = checkJ9Object(javaVM, newObjectPtr, &objectRegion, _cycle->getCheckFlags());680}681682if (J9MODRON_GCCHK_RC_OK == result) {683/* Object is OK. Record it in the cache so we can short circuit if we see it again */684_checkedObjectCache[cacheIndex] = objectPtr;685}686687return result;688}689690/**691* Verify a class.692*693* @param clazz the class to be verified694* @param segment the class memory segment which contains the class695*696* @return #J9MODRON_SLOT_ITERATOR_OK697*/698UDATA699GC_CheckEngine::checkClassHeap(J9JavaVM *javaVM, J9Class *clazz, J9MemorySegment *segment)700{701MM_GCExtensions * extensions = MM_GCExtensions::getExtensions(javaVM);702UDATA result;703volatile j9object_t *slotPtr;704705/*706* Verify that this is, in fact, a class707*/708result = checkJ9Class(javaVM, clazz, segment, _cycle->getCheckFlags());709if (J9MODRON_GCCHK_RC_OK != result) {710GC_CheckError error(clazz, _cycle, _currentCheck, "Class ", result, _cycle->nextErrorCount());711_reporter->report(&error);712}713714/*715* Process object slots in the class716*/717GC_ClassIterator classIterator(extensions, clazz);718while((slotPtr = classIterator.nextSlot()) != NULL) {719int state = classIterator.getState();720721J9Object *objectPtr = *slotPtr;722723result = checkObjectIndirect(javaVM, objectPtr);724725if (J9MODRON_GCCHK_RC_OK != result) {726const char *elementName = "";727728switch (state) {729case classiterator_state_statics:730elementName = "static "; break;731case classiterator_state_constant_pool:732elementName = "constant "; break;733case classiterator_state_slots:734elementName = "slots "; break;735case classiterator_state_callsites:736elementName = "callsite "; break;737}738GC_CheckError error(clazz, (void*)slotPtr, _cycle, _currentCheck, elementName, result, _cycle->nextErrorCount());739_reporter->report(&error);740return J9MODRON_SLOT_ITERATOR_OK;741}742if (extensions->isStandardGC()) {743#if defined(J9VM_GC_GENERATIONAL)744/* If the slot has its old bit OFF, the class's remembered bit should be ON */745if (objectPtr && !extensions->isOld(objectPtr)) {746if (!extensions->objectModel.isRemembered((J9Object*)clazz->classObject)) {747GC_CheckError error(clazz, (void*)slotPtr, _cycle, _currentCheck, "Class ", J9MODRON_GCCHK_RC_REMEMBERED_SET_OLD_OBJECT, _cycle->nextErrorCount());748_reporter->report(&error);749return J9MODRON_SLOT_ITERATOR_OK;750}751}752#endif /* J9VM_GC_GENERATIONAL */753}754}755756if (J9MODRON_GCCHK_RC_OK != checkClassStatics(javaVM, clazz)) {757return J9MODRON_SLOT_ITERATOR_OK;758}759760J9Class* replaced = clazz->replacedClass;761if (NULL != replaced) {762/* if class replaces another class the replaced class must have J9AccClassHotSwappedOut flag set */763if (0 == (J9CLASS_FLAGS(replaced) & J9AccClassHotSwappedOut)) {764GC_CheckError error(clazz, (void*)&(clazz->replacedClass), _cycle, _currentCheck, "Class ", J9MODRON_GCCHK_RC_REPLACED_CLASS_HAS_NO_HOTSWAP_FLAG, _cycle->nextErrorCount());765_reporter->report(&error);766return J9MODRON_SLOT_ITERATOR_OK;767}768}769770/*771* Process class slots in the class772*/773GC_ClassIteratorClassSlots classIteratorClassSlots(javaVM, clazz);774J9Class *classPtr;775while (NULL != (classPtr = classIteratorClassSlots.nextSlot())) {776int state = classIteratorClassSlots.getState();777const char *elementName = "";778779result = J9MODRON_GCCHK_RC_OK;780781switch (state) {782case classiteratorclassslots_state_constant_pool:783result = checkJ9ClassPointer(javaVM, classPtr);784elementName = "constant ";785break;786case classiteratorclassslots_state_superclasses:787result = checkJ9ClassPointer(javaVM, classPtr);788elementName = "superclass ";789break;790case classiteratorclassslots_state_interfaces:791result = checkJ9ClassPointer(javaVM, classPtr);792elementName = "interface ";793break;794case classiteratorclassslots_state_array_class_slots:795result = checkJ9ClassPointer(javaVM, classPtr);796elementName = "array class ";797break;798case classiteratorclassslots_state_flattened_class_cache_slots:799result = checkJ9ClassPointer(javaVM, classPtr);800elementName = "flattened class cache ";801break;802}803804if (J9MODRON_GCCHK_RC_OK != result) {805GC_CheckError error(clazz, &classPtr, _cycle, _currentCheck, elementName, result, _cycle->nextErrorCount());806_reporter->report(&error);807return J9MODRON_SLOT_ITERATOR_OK;808}809}810811return J9MODRON_SLOT_ITERATOR_OK;812}813814UDATA815GC_CheckEngine::checkClassStatics(J9JavaVM* vm, J9Class* clazz)816{817UDATA result = J9MODRON_GCCHK_RC_OK;818bool validationRequired = true;819820if (0 != (J9CLASS_FLAGS(clazz) & J9AccClassHotSwappedOut)) {821/* if class has been hot swapped (J9AccClassHotSwappedOut bit is set) in Fast HCR,822* the ramStatics of the existing class may be reused. The J9ClassReusedStatics823* bit in J9Class->classFlags will be set if that's the case.824* In Extended HCR mode ramStatics might be not NULL and must be valid825* NOTE: If class is hot swapped and the value in ramStatics is NULL it is valid826* to have the correspondent ROM Class value in objectStaticCount field greater then 0827*/828if (J9GC_CLASS_IS_ARRAY(clazz)) {829/* j9arrayclass should not be hot swapped */830result = J9MODRON_GCCHK_RC_CLASS_HOT_SWAPPED_FOR_ARRAY;831GC_CheckError error(clazz, _cycle, _currentCheck, "Class ", result, _cycle->nextErrorCount());832_reporter->report(&error);833validationRequired = false;834}835836if (areExtensionsEnabled(vm)) {837/* This is Extended HSR mode so hot swapped class might have NULL in ramStatics field */838if (NULL == clazz->ramStatics) {839validationRequired = false;840}841}842if (J9ClassReusedStatics == (J9CLASS_EXTENDED_FLAGS(clazz) & J9ClassReusedStatics)) {843/* This case can also occur when running -Xint with extensions enabled */844validationRequired = false;845}846}847848if (validationRequired) {849J9VMThread* currentThread = vm->internalVMFunctions->currentVMThread(vm);850J9ClassLoader* classLoader = clazz->classLoader;851J9ROMClass *romClazz = clazz->romClass;852J9ROMFieldWalkState state;853854UDATA numberOfReferences = 0;855j9object_t *sectionStart = NULL;856j9object_t *sectionEnd = NULL;857858/*859* Note: we have no special recognition for J9ArrayClass here860* J9ArrayClass does not have a ramStatics field but something else at this place861* so direct check (NULL != clazz->ramStatics) would not be correct,862* however romClazz->objectStaticCount must be 0 for this case863*/864if (0 != romClazz->objectStaticCount) {865sectionStart = (j9object_t *)clazz->ramStatics;866sectionEnd = sectionStart + romClazz->objectStaticCount;867}868869J9ROMFieldShape* romFieldCursor = romFieldsStartDo(romClazz, &state);870871/* Iterate all fields of ROM Class looking to statics fields pointed to java objects */872while (NULL != romFieldCursor) {873/* interested in static fields only */874if (romFieldCursor->modifiers & J9AccStatic) {875J9UTF8* nameUTF = J9ROMFIELDSHAPE_NAME(romFieldCursor);876J9UTF8* sigUTF = J9ROMFIELDSHAPE_SIGNATURE(romFieldCursor);877878/* interested in objects and all kinds of arrays */879if ((IS_REF_OR_VAL_SIGNATURE(J9UTF8_DATA(sigUTF)[0]))880|| ('[' == J9UTF8_DATA(sigUTF)[0])881) {882numberOfReferences += 1;883884/* get address of next field */885j9object_t* address = (j9object_t*)vm->internalVMFunctions->staticFieldAddress(currentThread, clazz, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF), J9UTF8_DATA(sigUTF), J9UTF8_LENGTH(sigUTF), NULL, NULL, J9_LOOK_NO_JAVA, NULL);886887/* an address must be in gc scan range */888if (!((address >= sectionStart) && (address < sectionEnd))) {889result = J9MODRON_GCCHK_RC_CLASS_STATICS_REFERENCE_IS_NOT_IN_SCANNING_RANGE;890GC_CheckError error(clazz, address, _cycle, _currentCheck, "Class ", result, _cycle->nextErrorCount());891_reporter->report(&error);892}893894/* check only if we have an object */895if (NULL != *address) {896U_8* toSearchString = J9UTF8_DATA(sigUTF);897UDATA toSearchLength = J9UTF8_LENGTH(sigUTF);898899if ('L' == J9UTF8_DATA(sigUTF)[0]) {900/* Convert signature to class name:901* Entering 'L' as well as closing ';' must be removed to get a proper class name902*/903toSearchString += 1;904toSearchLength -= 2;905}906907J9Class* classToCast = vm->internalVMFunctions->internalFindClassUTF8(currentThread, toSearchString, toSearchLength, classLoader, J9_FINDCLASS_FLAG_EXISTING_ONLY);908909/*910* If class with name extracted from RAM Static field's signature is not found in current classloader (classToCast == NULL)911* unfortunately it is no way to find it. Skip check for this case.912* However if class found - it must fit object's class913*/914if (NULL != classToCast) {915if (0 == instanceOfOrCheckCast(J9GC_J9OBJECT_CLAZZ_VM(*address, vm), classToCast)) {916result = J9MODRON_GCCHK_RC_CLASS_STATICS_FIELD_POINTS_WRONG_OBJECT;917GC_CheckError error(clazz, address, _cycle, _currentCheck, "Class ", result, _cycle->nextErrorCount());918_reporter->report(&error);919}920}921}922}923}924romFieldCursor = romFieldsNextDo(&state);925}926927if (numberOfReferences != romClazz->objectStaticCount) {928result = J9MODRON_GCCHK_RC_CLASS_STATICS_WRONG_NUMBER_OF_REFERENCES;929GC_CheckError error(clazz, _cycle, _currentCheck, "Class ", result, _cycle->nextErrorCount());930_reporter->report(&error);931}932}933934return result;935}936937/**938* Verify a slot (double-indirect object pointer) in the object heap.939*940* @param objectIndirect the slot to be verified941* @param segment the segment containing the object whose slot is being verified942* @param objectIndirectBase the object whose slot is being verified943*944* @return #J9MODRON_SLOT_ITERATOR_OK945*/946UDATA947GC_CheckEngine::checkSlotObjectHeap(J9JavaVM *javaVM, J9Object *objectPtr, fj9object_t *objectIndirect, J9MM_IterateRegionDescriptor *regionDesc, J9Object *objectIndirectBase)948{949MM_GCExtensions * extensions = MM_GCExtensions::getExtensions(javaVM);950951if (NULL == objectPtr) {952return J9MODRON_SLOT_ITERATOR_OK;953}954955UDATA result = checkObjectIndirect(javaVM, objectPtr);956957/* might the heap include dark matter? If so, ignore most errors */958if (_cycle->getMiscFlags() & J9MODRON_GCCHK_MISC_DARKMATTER) {959/* only report a subset of errors -- the rest are expected to be found in dark matter */960switch (result) {961case J9MODRON_GCCHK_RC_OK:962case J9MODRON_GCCHK_RC_UNALIGNED:963case J9MODRON_GCCHK_RC_STACK_OBJECT:964break;965966/* These errors are unlikely, but not impossible to find in dark matter.967* Leave them enabled because they can help find real corruption968*/969case J9MODRON_GCCHK_RC_NOT_FOUND: /* can happen due to contraction */970break;971972/* other errors in possible dark matter are expected, so ignore them and don't973* investigate this pointer any further974*/975default:976return J9MODRON_SLOT_ITERATOR_OK;977}978}979980if (J9MODRON_GCCHK_RC_OK != result) {981const char *elementName = extensions->objectModel.isIndexable(objectIndirectBase) ? "IObject " : "Object ";982GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, (char *)elementName, result, _cycle->nextErrorCount());983_reporter->report(&error);984return J9MODRON_SLOT_ITERATOR_OK;985}986987#if defined(J9VM_GC_GENERATIONAL)988if (MM_GCExtensions::getExtensions(javaVM)->scavengerEnabled) {989/* Old objects with references to newspace should have their remembered bit ON */990/* TODO: add a quick check to see if the object is in same region as the referring object? */991J9MM_IterateRegionDescriptor objectRegion;992if (!findRegionForPointer(javaVM, objectPtr, &objectRegion)) {993/* should be impossible, since checkObjectIndirect() already verified that the object exists */994const char *elementName = extensions->objectModel.isIndexable(objectIndirectBase) ? "IObject " : "Object ";995GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, (char *)elementName, J9MODRON_GCCHK_RC_NOT_FOUND, _cycle->nextErrorCount());996_reporter->report(&error);997return J9MODRON_SLOT_ITERATOR_OK;998}999UDATA regionType = ((MM_HeapRegionDescriptor*)regionDesc->id)->getTypeFlags();1000UDATA objectRegionType = ((MM_HeapRegionDescriptor*)objectRegion.id)->getTypeFlags();10011002if (objectPtr && (regionType & MEMORY_TYPE_OLD) && (objectRegionType & MEMORY_TYPE_NEW) && !extensions->objectModel.isRemembered(objectIndirectBase)) {1003const char *elementName = extensions->objectModel.isIndexable(objectIndirectBase) ? "IObject " : "Object ";1004GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, (char *)elementName, J9MODRON_GCCHK_RC_NEW_POINTER_NOT_REMEMBERED, _cycle->nextErrorCount());1005_reporter->report(&error);1006return J9MODRON_SLOT_ITERATOR_OK;1007}10081009/* Old objects that point to objects with old bit OFF should have remembered bit ON */1010if (objectPtr && (regionType & MEMORY_TYPE_OLD) && !extensions->isOld(objectPtr) && !extensions->objectModel.isRemembered(objectIndirectBase)) {1011const char *elementName = extensions->objectModel.isIndexable(objectIndirectBase) ? "IObject " : "Object ";1012GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, (char *)elementName, J9MODRON_GCCHK_RC_REMEMBERED_SET_OLD_OBJECT, _cycle->nextErrorCount());1013_reporter->report(&error);1014return J9MODRON_SLOT_ITERATOR_OK;1015}1016}1017#endif /* J9VM_GC_GENERATIONAL */10181019return J9MODRON_SLOT_ITERATOR_OK;1020}10211022/**1023* Verify an object that was encountered directly while walking the heap.1024* Perform some basic checks on the object by calling @ref checkJ9Object,1025* and if the object appears to be valid, walk its slots and verify each1026* of them. We must be very careful here to avoid crashing gccheck itself.1027*1028* @param object the object to verify1029* @regionDesc the region which contains the object1030*1031* @return #J9MODRON_SLOT_ITERATOR_OK on success, #J9MODRON_SLOT_ITERATOR_UNRECOVERABLE_ERROR on failure1032*/1033UDATA1034GC_CheckEngine::checkObjectHeap(J9JavaVM *javaVM, J9MM_IterateObjectDescriptor *objectDesc, J9MM_IterateRegionDescriptor *regionDesc)1035{1036MM_GCExtensions * extensions = MM_GCExtensions::getExtensions(javaVM);1037J9Class* clazz = NULL;1038UDATA result = J9MODRON_SLOT_ITERATOR_OK;10391040/* If we encounter a hole with size 0, the heap walk will enter an infinite loop -- prevent this. */1041/* Size of hole can not be larger then rest of the region */1042if (FALSE == objectDesc->isObject) {1043if ((0 == objectDesc->size) || (objectDesc->size > ((UDATA)regionDesc->regionStart + regionDesc->regionSize - (UDATA)objectDesc->object))) {1044GC_CheckError error(objectDesc->object, _cycle, _currentCheck, "Object ", J9MODRON_GCCHK_RC_DEAD_OBJECT_SIZE, _cycle->nextErrorCount());1045_reporter->report(&error);1046_reporter->reportHeapWalkError(&error, _lastHeapObject1, _lastHeapObject2, _lastHeapObject3);1047return J9MODRON_SLOT_ITERATOR_UNRECOVERABLE_ERROR;1048}1049return J9MODRON_SLOT_ITERATOR_OK;1050}10511052result = checkJ9Object(javaVM, objectDesc->object, regionDesc, _cycle->getCheckFlags());1053if (J9MODRON_GCCHK_RC_OK != result) {1054const char *elementName = extensions->objectModel.isIndexable(objectDesc->object) ? "IObject " : "Object ";1055GC_CheckError error(objectDesc->object, _cycle, _currentCheck, (char *)elementName, result, _cycle->nextErrorCount());1056_reporter->report(&error);1057_reporter->reportHeapWalkError(&error, _lastHeapObject1, _lastHeapObject2, _lastHeapObject3);1058return J9MODRON_SLOT_ITERATOR_UNRECOVERABLE_ERROR;1059}10601061clazz = J9GC_J9OBJECT_CLAZZ_VM(objectDesc->object, javaVM);1062result = checkJ9ClassPointer(javaVM, clazz, true);1063if (J9MODRON_GCCHK_RC_OK == result) {1064ObjectSlotIteratorCallbackUserData userData;1065userData.engine = this;1066userData.regionDesc = regionDesc;1067userData.result = result;1068javaVM->memoryManagerFunctions->j9mm_iterate_object_slots(javaVM, _portLibrary, objectDesc, j9mm_iterator_flag_exclude_null_refs, check_objectSlotsCallback, &userData);1069result = userData.result;1070}10711072/* check Ownable Synchronizer Object consistency */1073if ((OBJECT_HEADER_SHAPE_MIXED == J9GC_CLASS_SHAPE(clazz)) && (0 != (J9CLASS_FLAGS(clazz) & J9AccClassOwnableSynchronizer))) {1074if (NULL == extensions->accessBarrier->isObjectInOwnableSynchronizerList(objectDesc->object)) {1075PORT_ACCESS_FROM_PORT(_portLibrary);1076j9tty_printf(PORTLIB, " <gc check: found Ownable SynchronizerObject %p is not on the list >\n", objectDesc->object);1077} else {1078_ownableSynchronizerObjectCountOnHeap += 1;1079}1080}10811082if (J9MODRON_SLOT_ITERATOR_OK == result) {1083/* this heap object is OK. Record it in the cache in case we find a pointer to it soon */1084UDATA cacheIndex = ((UDATA)objectDesc->object) % OBJECT_CACHE_SIZE;1085_checkedObjectCache[cacheIndex] = objectDesc->object;1086}10871088return result;1089}10901091/**1092* Verify a slot (double-indirect object pointer).1093*1094* @param objectIndirect the slot to be verified1095* @param objectIndirectBase the object which contains the slot1096*1097* @return #J9MODRON_SLOT_ITERATOR_OK1098*/1099UDATA1100GC_CheckEngine::checkSlotVMThread(J9JavaVM *javaVM, J9Object **objectIndirect, void *objectIndirectBase, UDATA objectType, GC_VMThreadIterator *vmthreadIterator)1101{1102J9Object *objectPtr = *objectIndirect;11031104UDATA result = checkObjectIndirect(javaVM, objectPtr);1105if (J9MODRON_GCCHK_RC_STACK_OBJECT == result) {1106if (vmthreaditerator_state_monitor_records != vmthreadIterator->getState()) {1107GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount(), objectType);1108_reporter->report(&error);1109}1110} else if (J9MODRON_GCCHK_RC_OK != result) {1111GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount(), objectType);1112_reporter->report(&error);1113}1114return J9MODRON_SLOT_ITERATOR_OK;1115}11161117/**1118* Verify a slot (double-indirect object pointer) on the stack.1119*1120* @param objectIndirect the slot to be verified1121* @param vmThread pointer to the thread whose stack contains the slot1122*1123* @return #J9MODRON_SLOT_ITERATOR_OK1124*/1125UDATA1126GC_CheckEngine::checkSlotStack(J9JavaVM *javaVM, J9Object **objectIndirect, J9VMThread *vmThread, const void *stackLocation)1127{1128J9Object *objectPtr = *objectIndirect;11291130UDATA result = checkObjectIndirect(javaVM, objectPtr);11311132if (J9MODRON_GCCHK_RC_STACK_OBJECT == result) {1133result = checkStackObject(javaVM, objectPtr);1134}1135if (J9MODRON_GCCHK_RC_OK != result) {1136GC_CheckError error(vmThread, objectIndirect, stackLocation, _cycle, _currentCheck, result, _cycle->nextErrorCount());1137_reporter->report(&error);11381139return J9MODRON_SLOT_ITERATOR_RECOVERABLE_ERROR;1140}1141return J9MODRON_SLOT_ITERATOR_OK;1142}11431144/**1145* Verify a slot in a pool.1146*1147* @param objectIndirect the slot to be verified1148* @param objectIndirectBase the "object" containing the slot. Maybe or may not1149* be an actual <code>J9Object</code> (e.g. could be a <code>J9ClassLoader</code>1150* struct). Note that this must be a remote pointer.1151*1152* @todo objectIndirectBase pointer should probably be changed to void *1153*1154* @return #J9MODRON_SLOT_ITERATOR_OK1155*/1156UDATA1157GC_CheckEngine::checkSlotPool(J9JavaVM *javaVM, J9Object **objectIndirect, void *objectIndirectBase)1158{1159J9Object *objectPtr = *objectIndirect;1160UDATA result = checkObjectIndirect(javaVM, objectPtr);1161if (J9MODRON_GCCHK_RC_OK != result) {1162GC_CheckError error(objectIndirectBase, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount(), check_type_other);1163_reporter->report(&error);1164}1165return J9MODRON_SLOT_ITERATOR_OK;1166}11671168/**1169* Verify a remembered set slot.1170*1171* @param objectIndirect the slot to be verified1172* @param objectIndirectBase the sublist puddle which contains the slot1173*1174* @return #J9MODRON_SLOT_ITERATOR_OK1175*/1176UDATA1177GC_CheckEngine::checkSlotRememberedSet(J9JavaVM *javaVM, J9Object **objectIndirect, MM_SublistPuddle *puddle)1178{1179MM_GCExtensions* extensions = MM_GCExtensions::getExtensions(javaVM);1180J9Object *objectPtr = *objectIndirect;11811182if (_cycle->getMiscFlags() & J9MODRON_GCCHK_MISC_MIDSCAVENGE) {1183/* during a scavenge, some RS entries may be tagged -- remove the tag */1184if ( DEFERRED_RS_REMOVE_FLAG == (((UDATA)objectPtr) & DEFERRED_RS_REMOVE_FLAG) ) {1185objectPtr = (J9Object*)( ((UDATA)objectPtr) & ~(UDATA)DEFERRED_RS_REMOVE_FLAG );1186}1187}11881189UDATA result = checkObjectIndirect(javaVM, objectPtr);1190if (J9MODRON_GCCHK_RC_OK != result) {1191GC_CheckError error(puddle, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount());1192_reporter->report(&error);1193return J9MODRON_SLOT_ITERATOR_OK;1194}11951196/* Additional checks for the remembered set */1197if (NULL != objectPtr) {1198J9MM_IterateRegionDescriptor objectRegion;1199if (!findRegionForPointer(javaVM, objectPtr, &objectRegion)) {1200/* shouldn't happen, since checkObjectIndirect() already verified this object */1201GC_CheckError error(puddle, objectIndirect, _cycle, _currentCheck, J9MODRON_GCCHK_RC_NOT_FOUND, _cycle->nextErrorCount());1202_reporter->report(&error);1203return J9MODRON_SLOT_ITERATOR_OK;1204}12051206/* we shouldn't have newspace references in the remembered set */1207UDATA regionType = ((MM_HeapRegionDescriptor*)objectRegion.id)->getTypeFlags();12081209if (regionType & MEMORY_TYPE_NEW) {1210GC_CheckError error(puddle, objectIndirect, _cycle, _currentCheck, J9MODRON_GCCHK_RC_REMEMBERED_SET_WRONG_SEGMENT, _cycle->nextErrorCount());1211_reporter->report(&error);1212return J9MODRON_SLOT_ITERATOR_OK;1213}12141215/* content of Remembered Set should be Old and Remembered */1216if ( !(extensions->isOld(objectPtr) && extensions->objectModel.isRemembered(objectPtr))) {1217GC_CheckError error(puddle, objectIndirect, _cycle, _currentCheck, J9MODRON_GCCHK_RC_REMEMBERED_SET_FLAGS, _cycle->nextErrorCount());1218_reporter->report(&error);1219_reporter->reportObjectHeader(&error, objectPtr, NULL);1220return J9MODRON_SLOT_ITERATOR_OK;1221}1222}12231224return J9MODRON_SLOT_ITERATOR_OK;1225}12261227/**1228* Verify a unfinalized object list slot.1229*1230* @param objectIndirect the slot to be verified1231* @param currentList the unfinalizedObjectList which contains the slot1232*1233* @return #J9MODRON_SLOT_ITERATOR_OK1234*/1235UDATA1236GC_CheckEngine::checkSlotUnfinalizedList(J9JavaVM *javaVM, J9Object **objectIndirect, MM_UnfinalizedObjectList *currentList)1237{1238J9Object *objectPtr = *objectIndirect;12391240UDATA result = checkObjectIndirect(javaVM, objectPtr);1241if (J9MODRON_GCCHK_RC_OK != result) {1242GC_CheckError error(currentList, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount());1243_reporter->report(&error);1244return J9MODRON_SLOT_ITERATOR_OK;1245}12461247return J9MODRON_SLOT_ITERATOR_OK;1248}12491250UDATA1251GC_CheckEngine::checkSlotOwnableSynchronizerList(J9JavaVM *javaVM, J9Object **objectIndirect, MM_OwnableSynchronizerObjectList *currentList)1252{1253J9Object *objectPtr = *objectIndirect;1254UDATA rc = J9MODRON_SLOT_ITERATOR_OK;12551256_ownableSynchronizerObjectCountOnList += 1;12571258UDATA result = checkObjectIndirect(javaVM, objectPtr);1259if (J9MODRON_GCCHK_RC_OK != result) {1260GC_CheckError error(currentList, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount());1261_reporter->report(&error);1262} else {1263J9Class *instanceClass = J9GC_J9OBJECT_CLAZZ_VM(objectPtr, javaVM);1264if (0 == (J9CLASS_FLAGS(instanceClass) & J9AccClassOwnableSynchronizer)) {1265GC_CheckError error(currentList, objectIndirect, _cycle, _currentCheck, J9MODRON_GCCHK_RC_INVALID_FLAGS, _cycle->nextErrorCount());1266_reporter->report(&error);1267}1268J9VMThread* currentThread = javaVM->internalVMFunctions->currentVMThread(javaVM);1269J9ClassLoader* classLoader = instanceClass->classLoader;1270const char* aosClassName = "java/util/concurrent/locks/AbstractOwnableSynchronizer";12711272J9Class* castClass = javaVM->internalVMFunctions->internalFindClassUTF8(currentThread, (U_8*) aosClassName, strlen(aosClassName), classLoader, J9_FINDCLASS_FLAG_EXISTING_ONLY);1273if (NULL != castClass) {1274if (0 == instanceOfOrCheckCast(instanceClass, castClass)) {1275GC_CheckError error(currentList, objectIndirect, _cycle, _currentCheck, J9MODRON_GCCHK_RC_OWNABLE_SYNCHRONIZER_INVALID_CLASS, _cycle->nextErrorCount());1276_reporter->report(&error);1277}1278}1279}1280return rc;1281}12821283/**1284* Verify a finalized object queue slot.1285*1286* @param objectIndirect the slot to be verified1287* @param listManager the MM_FinalizeListManager which contains the slot1288*1289* @return #J9MODRON_SLOT_ITERATOR_OK1290*/1291UDATA1292GC_CheckEngine::checkSlotFinalizableList(J9JavaVM *javaVM, J9Object **objectIndirect, GC_FinalizeListManager *listManager)1293{1294J9Object *objectPtr = *objectIndirect;12951296UDATA result = checkObjectIndirect(javaVM, objectPtr);1297if (J9MODRON_GCCHK_RC_OK != result) {1298GC_CheckError error(listManager, objectIndirect, _cycle, _currentCheck, result, _cycle->nextErrorCount());1299_reporter->report(&error);1300return J9MODRON_SLOT_ITERATOR_OK;1301}13021303return J9MODRON_SLOT_ITERATOR_OK;1304}13051306/**1307* Start of a check1308* This function should be called before any of the check functions in1309* the engine. It ensures that the heap is walkable and TLHs are flushed1310*/1311void1312GC_CheckEngine::startCheckCycle(J9JavaVM *javaVM, GC_CheckCycle *checkCycle)1313{1314_cycle = checkCycle;1315_currentCheck = NULL;1316#if defined(J9VM_GC_MODRON_SCAVENGER)1317_scavengerBackout = false;1318_rsOverflowState = false;1319#endif /* J9VM_GC_MODRON_SCAVENGER */1320clearPreviousObjects();1321clearRegionDescription(&_regionDesc);1322clearCheckedCache();13231324clearCountsForOwnableSynchronizerObjects();13251326/* Flush any VM level changes to prepare for a safe slot walk */1327TRIGGER_J9HOOK_MM_PRIVATE_WALK_HEAP_START(MM_GCExtensions::getExtensions(javaVM)->privateHookInterface, javaVM->omrVM);1328}13291330/**1331* End of a check1332* This function should be called at the end of a check. It triggers1333* the hook to inform interested parties that a heap walk has occurred.1334*/1335void GC_CheckEngine::endCheckCycle(J9JavaVM *javaVM)1336{1337TRIGGER_J9HOOK_MM_PRIVATE_WALK_HEAP_END(MM_GCExtensions::getExtensions(javaVM)->privateHookInterface, javaVM->omrVM);1338}13391340/**1341* Advance to the next stage of checking.1342* Sets the context for the next stage of checking. Called every time verification1343* moves to a new structure.1344*1345* @param check Pointer to the check we're about to start1346*/1347void1348GC_CheckEngine::startNewCheck(GC_Check *check)1349{1350_currentCheck = check;1351clearPreviousObjects();1352}13531354/**1355* Ensure the GC internal scope pointers refer to objects within the scope.1356*1357* @param scopedMemorySpace The memory space with the internal pointers to verify.1358* @param regionDesc The region descriptor which should contain all pointers.1359*/13601361/**1362* Create new instance of check object, using the specified reporter object,1363* and the specified port library.1364*/1365GC_CheckEngine *1366GC_CheckEngine::newInstance(J9JavaVM *javaVM, GC_CheckReporter *reporter)1367{1368MM_Forge *forge = MM_GCExtensions::getExtensions(javaVM)->getForge();13691370GC_CheckEngine *check = (GC_CheckEngine *)forge->allocate(sizeof(GC_CheckEngine), MM_AllocationCategory::DIAGNOSTIC, J9_GET_CALLSITE());1371if (check) {1372check = new(check) GC_CheckEngine(javaVM, reporter);1373if (!check->initialize()) {1374check->kill();1375check = NULL;1376}1377}1378return check;1379}13801381bool1382GC_CheckEngine::initialize()1383{1384clearPreviousObjects();1385clearRegionDescription(&_regionDesc);1386clearCheckedCache();1387return true;1388}13891390void1391GC_CheckEngine::kill()1392{1393MM_Forge *forge = MM_GCExtensions::getExtensions(_javaVM)->getForge();1394if(_reporter) {1395_reporter->kill();1396}1397forge->free(this);1398}13991400/**1401* Determine whether or not the a verbose stack dump should always be displayed.1402*1403* @return true if verbose stack dump is always displayed.1404* @return false if verbose stack dump is only displayed on error.1405*/1406bool1407GC_CheckEngine::isStackDumpAlwaysDisplayed()1408{1409if (NULL == _cycle) {1410return false;1411}1412return (J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK == (_cycle->getMiscFlags() & J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK));1413}14141415/**1416* Copy the information from one regionDescription to the other.1417* @param from - the source region1418* @param to - the destination region1419*1420*/1421void1422GC_CheckEngine::copyRegionDescription(J9MM_IterateRegionDescriptor* from, J9MM_IterateRegionDescriptor* to)1423{1424to->name = from->name;1425to->id = from->id;1426to->objectAlignment = from->objectAlignment;1427to->objectMinimumSize = from->objectMinimumSize;1428to->regionStart = from->regionStart;1429to->regionSize = from->regionSize;1430}14311432/**1433* Clear the region1434* @param toClear - the region to clear1435*1436*/1437void1438GC_CheckEngine::clearRegionDescription(J9MM_IterateRegionDescriptor* toClear)1439{1440memset(toClear, 0, sizeof(J9MM_IterateRegionDescriptor));1441}14421443void1444GC_CheckEngine::clearCheckedCache()1445{1446memset(_checkedClassCache, 0, sizeof(_checkedClassCache));1447memset(_checkedClassCacheAllowUndead, 0, sizeof(_checkedClassCacheAllowUndead));1448memset(_checkedObjectCache, 0, sizeof(_checkedObjectCache));1449}14501451static jvmtiIterationControl1452check_objectSlotsCallback(J9JavaVM *javaVM, J9MM_IterateObjectDescriptor *objectDesc, J9MM_IterateObjectRefDescriptor *refDesc, void *userData)1453{1454ObjectSlotIteratorCallbackUserData* castUserData = (ObjectSlotIteratorCallbackUserData*)userData;1455castUserData->result = castUserData->engine->checkSlotObjectHeap(javaVM, (J9Object *)refDesc->object, (fj9object_t*)refDesc->fieldAddress, castUserData->regionDesc, objectDesc->object);1456if (J9MODRON_GCCHK_RC_OK != castUserData->result) {1457return JVMTI_ITERATION_ABORT;1458}1459return JVMTI_ITERATION_CONTINUE;1460}14611462/**1463* Determine whether or not the given object is contained in the given region1464*1465* @return true if objectPtr is contained in the given region1466* @return false otherwise1467*/1468static bool1469isPointerInRegion(void *pointer, J9MM_IterateRegionDescriptor *regionDesc)1470{1471UDATA regionStart = (UDATA)regionDesc->regionStart;1472UDATA regionEnd = regionStart + regionDesc->regionSize;1473UDATA address = (UDATA)pointer;14741475return ((address >= regionStart) && (address < regionEnd));1476}147714781479