Path: blob/master/runtime/gc_base/ObjectCheck.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2020 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#include "ObjectCheck.hpp"2324#include "ClassModel.hpp"25#include "GCExtensions.hpp"26#include "Heap.hpp"27#include "HeapRegionIterator.hpp"28#include "HeapRegionDescriptor.hpp"29#include "ObjectModel.hpp"30#include "SegmentIterator.hpp"3132extern "C" {33/**34* Check if the pointer is a valid class. Helper function for j9gc_ext_check_is_valid_heap_object.35* @param javaVM36* @param ptr the pointer to check if it is a valid class37* @param flags set J9OBJECTCHECK_FLAGS_* to control checking behaviour.38* @return one of J9OBJECTCHECK_* depending if the class is valid, invalid or looks like a forwarded pointer39* @ingroup GC_Base40*/41static UDATA42isValidClass(J9JavaVM *javaVM, J9Class *ptr, UDATA flags) {43GC_SegmentIterator segmentIterator(javaVM->classMemorySegments, MEMORY_TYPE_RAM_CLASS);44J9MemorySegment *segment;4546/* class field can't be NULL */47if (NULL == ptr) {48return J9OBJECTCHECK_INVALID;49}5051/* check alignment */52if (0 != ((UDATA)ptr & (sizeof(UDATA) - 1))) {53return J9OBJECTCHECK_INVALID;54}5556/* We are not guarantee to have exclusive access at this point -- we need to mutex57* so that we don't pick up a segment while it is being added.58*/59#if defined(J9VM_THR_PREEMPTIVE)60omrthread_monitor_enter(javaVM->classMemorySegments->segmentMutex);61#endif /* J9VM_THR_PREEMPTIVE */6263/* try to find the segment that this class starts in */64while(NULL != (segment = segmentIterator.nextSegment())) {65/* is the pointer in this segment? */66if ((segment->heapBase <= (U_8 *)ptr) && ((U_8 *)ptr < segment->heapAlloc)) {67break;68}69}7071#if defined(J9VM_THR_PREEMPTIVE)72omrthread_monitor_exit(javaVM->classMemorySegments->segmentMutex);73#endif /* J9VM_THR_PREEMPTIVE */7475/* pointer is not in class segment */76if (NULL == segment) {77return J9OBJECTCHECK_INVALID;78}7980/* ensure that the class header fits into the segment */81if ((segment->heapAlloc - (U_8 *)ptr) < (ptrdiff_t)sizeof(J9Class)) {82return J9OBJECTCHECK_INVALID;83}8485return J9OBJECTCHECK_CLASS;86}8788/**89* Check if the pointer is a valid object in the object heap.90* @param javaVM91* @param ptr the pointer to check if it is a valid object92* @param flags set J9OBJECTCHECK_FLAGS_* to control checking behaviour.93* @return one of J9OBJECTCHECK_* depending if the object is valid, invalid or looks like it was forwarded.94* @ingroup GC_Base95*/96UDATA97j9gc_ext_check_is_valid_heap_object(J9JavaVM *javaVM, J9Object *ptr, UDATA flags)98{99/* check alignment */100if (0 != ((UDATA)ptr & (sizeof(UDATA) - 1) )) {101return J9OBJECTCHECK_INVALID;102}103104UDATA retVal = 0;105void *lowAddress = NULL;106void *highAddress = NULL;107/* look up the region containing the object for checking that it is correctly contained */108MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(javaVM);109MM_Heap *heap = extensions->heap;110MM_HeapRegionManager *regionManager = heap->getHeapRegionManager();111GC_HeapRegionIterator regionIterator(regionManager);112MM_HeapRegionDescriptor *region = NULL;113114/* try to find the region that this class starts in */115while(NULL != (region = regionIterator.nextRegion())) {116/* is the pointer in this segment? */117lowAddress = region->getLowAddress();118highAddress = region->getHighAddress();119if ((lowAddress <= ptr) && (ptr < highAddress)) {120break;121}122}123124/* pointer is not in a region, this may really be a pointer to a class */125if (NULL == region) {126return J9OBJECTCHECK_INVALID;127}128129/* ensure that the object header fits into the segment */130if (((UDATA)highAddress - (UDATA)ptr) < J9JAVAVM_OBJECT_HEADER_SIZE(javaVM)) {131return J9OBJECTCHECK_INVALID;132}133134/* NOTE: Individual fields of the header will be queried multiple times135* If they change underneath us, we may want to take a snapshot136* of the header before querying them137*/138139/* ensure that its class is valid */140retVal = isValidClass(javaVM, J9GC_J9OBJECT_CLAZZ_VM(ptr, javaVM), flags);141if (J9OBJECTCHECK_CLASS != retVal) {142return retVal;143}144145/* ensure that the shape is correct */146if (!extensions->objectModel.checkIndexableFlag(ptr)) {147return J9OBJECTCHECK_INVALID;148}149150if (extensions->objectModel.isObjectArray(ptr)151|| extensions->objectModel.isPrimitiveArray(ptr)) {152/* ensure that the array size fits into the segment */153if (((UDATA)highAddress - (UDATA)ptr) < J9JAVAVM_CONTIGUOUS_HEADER_SIZE(javaVM)) {154return J9OBJECTCHECK_INVALID;155}156}157158/* ensure that the full object fits into the segment159* This must be done after knowing the class is valid, as we reach into the class to get the instance size160* Note: there are two cases for getSizeInBytesWithHeader:161* IndexableObject: The size is retrieved from the buffered object in the fourth slot which has already been162* cached, and range checked.163* MixedObject: The size is retrieved from the buffered class pointer. The class pointer won't have changed164* since checking it to be valid, however the size itself within the class memory may have changed. Since165* this is a range check it "does not matter", we know we will be able to dereference the memory.166*/167if (((UDATA)highAddress - (UDATA)ptr) < extensions->objectModel.getSizeInBytesWithHeader(ptr)) {168return J9OBJECTCHECK_INVALID;169}170171return J9OBJECTCHECK_OBJECT;172}173} /* extern "C" */174175176