agent/native/ext/elastic_apm_alloc.h (219 lines of code) (raw):

/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #pragma once #include <stdbool.h> #include "basic_types.h" #include "MemoryTracker.h" #include "internal_checks.h" #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) # include "platform.h" // ELASTIC_APM_CAPTURE_STACK_TRACE #endif #ifndef ELASTIC_APM_PEMALLOC_FUNC # include <php.h> # define ELASTIC_APM_PEMALLOC_FUNC pemalloc # define ELASTIC_APM_PEFREE_FUNC pefree #else // Declare to avoid warnings void* ELASTIC_APM_PEMALLOC_FUNC ( size_t requestedSize, bool isPersistent ); void ELASTIC_APM_PEFREE_FUNC ( void* allocatedBlock, bool isPersistent ); #endif #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_BEFORE( requestedSize, /* out */ actuallyRequestedSizeVar ) \ MemoryTracker* const memTracker = getGlobalMemoryTracker(); \ void* stackTraceAddressesBuffer[ maxCaptureStackTraceDepth ]; \ size_t stackTraceAddressesCount = 0; \ const bool isMemoryTrackingEnabledCached = isMemoryTrackingEnabled( memTracker ); \ if ( isMemoryTrackingEnabledCached ) \ { \ if ( shouldCaptureStackTrace( memTracker ) ) \ { \ stackTraceAddressesCount = ELASTIC_APM_CAPTURE_STACK_TRACE( \ &(stackTraceAddressesBuffer[ 0 ]), \ ELASTIC_APM_STATIC_ARRAY_SIZE( stackTraceAddressesBuffer ) ); \ } \ (actuallyRequestedSizeVar) = \ memoryTrackerCalcSizeToAlloc( memTracker, (requestedSize), stackTraceAddressesCount ); \ } #define ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_AFTER( isString, requestedSize, actuallyRequestedSize, isPersistent ) \ if ( isMemoryTrackingEnabledCached ) \ { \ memoryTrackerAfterAlloc( \ memTracker, \ (phpAllocIfFailedGotoTmpPtr), \ (requestedSize), \ (isPersistent), \ (actuallyRequestedSize), \ ELASTIC_APM_STRING_LITERAL_TO_VIEW( __FILE__ ), \ __LINE__, \ isString, \ &( stackTraceAddressesBuffer[ 0 ] ), \ stackTraceAddressesCount ); \ } #else // #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_BEFORE( requestedSize ) #define ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_AFTER( isString, requestedSize, isPersistent ) #endif // #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_ALLOC_IF_FAILED_DO_EX( type, isString, requestedSize, isPersistent, outPtr, doOnFailure ) \ do { \ size_t actuallyRequestedSize = (requestedSize); \ \ ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_BEFORE( requestedSize, /* out */ actuallyRequestedSize ) \ \ void* phpAllocIfFailedGotoTmpPtr = ELASTIC_APM_PEMALLOC_FUNC( actuallyRequestedSize, (isPersistent) ); \ if ( phpAllocIfFailedGotoTmpPtr == NULL ) \ { \ resultCode = resultOutOfMemory; \ doOnFailure; \ } \ (outPtr) = (type*)(phpAllocIfFailedGotoTmpPtr); \ \ ELASTIC_APM_PHP_ALLOC_MEMORY_TRACKING_AFTER( isString, requestedSize, actuallyRequestedSize, isPersistent ) \ } while ( 0 ) #define ELASTIC_APM_PHP_ALLOC_IF_FAILED_GOTO_EX( type, isString, requestedSize, isPersistent, outPtr ) \ ELASTIC_APM_PHP_ALLOC_IF_FAILED_DO_EX( type, isString, requestedSize, isPersistent, outPtr, /* doOnFailure: */ goto failure ) #define ELASTIC_APM_PEMALLOC_INSTANCE_IF_FAILED_GOTO( type, outPtr ) \ ELASTIC_APM_PHP_ALLOC_IF_FAILED_GOTO_EX( type, /* isString: */ false, sizeof( type ), /* isPersistent: */ true, outPtr ) #define ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_DO( type, isString, arrayNumberOfElements, isPersistent, outPtr, doOnFailure ) \ ELASTIC_APM_PHP_ALLOC_IF_FAILED_DO_EX( type, isString, sizeof( type ) * (arrayNumberOfElements), isPersistent, outPtr, doOnFailure ) #define ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_GOTO( type, isString, arrayNumberOfElements, isPersistent, outPtr ) \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_DO( type, isString, arrayNumberOfElements, isPersistent, outPtr, /* doOnFailure: */ goto failure ) #define ELASTIC_APM_EMALLOC_ARRAY_IF_FAILED_GOTO( type, arrayNumberOfElements, outPtr ) \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_GOTO( type, /* isString: */ false, arrayNumberOfElements, /* isPersistent */ false, outPtr ) #define ELASTIC_APM_PEMALLOC_ARRAY_IF_FAILED_GOTO( type, arrayNumberOfElements, outPtr ) \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_GOTO( type, /* isString: */ false, arrayNumberOfElements, /* isPersistent */ true, outPtr ) #define ELASTIC_APM_EMALLOC_STRING_IF_FAILED_GOTO( stringBufferSizeInclTermZero, outPtr ) \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_GOTO( char, /* isString: */ true, stringBufferSizeInclTermZero, /* isPersistent */ false, outPtr ) #define ELASTIC_APM_PEMALLOC_STRING_IF_FAILED_GOTO( stringBufferSizeInclTermZero, outPtr ) \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_GOTO( char, /* isString: */ true, stringBufferSizeInclTermZero, /* isPersistent */ true, outPtr ) #define ELASTIC_APM_PHP_ALLOC_DUP_STRING_IF_FAILED_DO( srcStr, isPersistent, outPtr, doOnFailure ) \ do { \ ELASTIC_APM_ASSERT( (srcStr) != NULL, "" ); \ char* elasticApmPemallocDupStringTempPtr = NULL; \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_DO( \ char, \ /* isString: */ true, \ strlen( (srcStr) ) + 1, \ isPersistent, \ elasticApmPemallocDupStringTempPtr, \ doOnFailure ); \ strcpy( elasticApmPemallocDupStringTempPtr, (srcStr) ); \ (outPtr) = elasticApmPemallocDupStringTempPtr; \ } while ( 0 ) #define ELASTIC_APM_PHP_ALLOC_DUP_STRING_IF_FAILED_GOTO( srcStr, isPersistent, outPtr ) \ ELASTIC_APM_PHP_ALLOC_DUP_STRING_IF_FAILED_DO( srcStr, isPersistent, outPtr, /* doOnFailure: */ goto failure ) #define ELASTIC_APM_EMALLOC_DUP_STRING_IF_FAILED_GOTO( srcStr, outPtr ) \ ELASTIC_APM_PHP_ALLOC_DUP_STRING_IF_FAILED_GOTO( srcStr, /* isPersistent */ false, outPtr ) #define ELASTIC_APM_PEMALLOC_DUP_STRING_IF_FAILED_GOTO( srcStr, outPtr ) \ ELASTIC_APM_PHP_ALLOC_DUP_STRING_IF_FAILED_GOTO( srcStr, /* isPersistent */ true, outPtr ) #define ELASTIC_APM_PHP_ALLOC_DUP_STRING_VIEW_IF_FAILED_DO( srcStrBegin, srcStrLen, isPersistent, outPtr, doOnFailure ) \ do { \ ELASTIC_APM_ASSERT( (srcStrBegin) != NULL, "" ); \ char* elasticApmPemallocDupStringTempPtr = NULL; \ ELASTIC_APM_PHP_ALLOC_ARRAY_IF_FAILED_DO( \ char, \ /* isString: */ true, \ (srcStrLen) + 1, \ isPersistent, \ elasticApmPemallocDupStringTempPtr, \ doOnFailure ); \ strncpy( elasticApmPemallocDupStringTempPtr, (srcStrBegin), (srcStrLen) ); \ elasticApmPemallocDupStringTempPtr[ (srcStrLen) ] = '\0'; \ (outPtr) = elasticApmPemallocDupStringTempPtr; \ } while ( 0 ) #define ELASTIC_APM_PEMALLOC_DUP_STRING_VIEW_IF_FAILED_GOTO( srcStrBegin, srcStrLen, outPtr ) \ ELASTIC_APM_PHP_ALLOC_DUP_STRING_VIEW_IF_FAILED_DO( srcStrBegin, srcStrLen, /* isPersistent */ true, outPtr, /* doOnFailure: */ goto failure ) static const UInt32 poisonPattern = 0xDEADBEEF; static inline void poisonMemoryRange( Byte* rangeBegin, size_t rangeSize ) { const Byte* poisonPatternBegin = (const Byte*)&poisonPattern; ELASTIC_APM_FOR_EACH_INDEX( i, rangeSize ) rangeBegin[ i ] = poisonPatternBegin[ i % sizeof( poisonPattern ) ]; } #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_FREE_MEMORY_TRACKING_BEFORE( requestedSize, isPersistent, ptr ) \ MemoryTracker* const memTracker = getGlobalMemoryTracker(); \ size_t originallyRequestedSize = 0; \ size_t possibleActuallyRequestedSize = 0; \ if ( isMemoryTrackingEnabled( memTracker ) ) \ { \ originallyRequestedSize = (requestedSize); \ possibleActuallyRequestedSize = originallyRequestedSize; \ memoryTrackerBeforeFree( memTracker, (ptr), originallyRequestedSize, (isPersistent), &possibleActuallyRequestedSize ); \ } \ \ if ( possibleActuallyRequestedSize != 0 && getGlobalInternalChecksLevel() >= internalChecksLevel_2 ) \ { \ if ( getGlobalInternalChecksLevel() > memoryTrackingLevel_eachAllocationWithStackTrace ) \ ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKER( memTracker ); \ \ poisonMemoryRange( (Byte*)(ptr), possibleActuallyRequestedSize ); \ \ if ( getGlobalInternalChecksLevel() > memoryTrackingLevel_eachAllocationWithStackTrace ) \ ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKER( memTracker ); \ } #else // #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_FREE_MEMORY_TRACKING_BEFORE( requestedSize, isPersistent, ptr ) #endif // #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 ) #define ELASTIC_APM_PHP_FREE_AND_SET_TO_NULL( type, requestedSize, isPersistent, ptr ) \ do { \ if ( (ptr) != NULL ) \ { \ ELASTIC_APM_PHP_FREE_MEMORY_TRACKING_BEFORE( requestedSize, isPersistent, ptr ) \ \ ELASTIC_APM_PEFREE_FUNC( (void*)(ptr), (isPersistent) ); \ (ptr) = (type*)(NULL); \ } \ } while ( 0 ) #define ELASTIC_APM_PEFREE_INSTANCE_AND_SET_TO_NULL( type, ptr ) \ ELASTIC_APM_PHP_FREE_AND_SET_TO_NULL( type, sizeof( type ), /* isPersistent */ true, ptr ) #define ELASTIC_APM_EFREE_ARRAY_AND_SET_TO_NULL( type, arrayNumberOfElements, ptr ) \ ELASTIC_APM_PHP_FREE_AND_SET_TO_NULL( type, sizeof( type ) * (arrayNumberOfElements), /* isPersistent */ false, ptr ) #define ELASTIC_APM_PEFREE_ARRAY_AND_SET_TO_NULL( type, arrayNumberOfElements, ptr ) \ ELASTIC_APM_PHP_FREE_AND_SET_TO_NULL( type, sizeof( type ) * (arrayNumberOfElements), /* isPersistent */ true, ptr ) #define ELASTIC_APM_EFREE_STRING_SIZE_AND_SET_TO_NULL( stringBufferSizeInclTermZero, ptr ) \ ELASTIC_APM_EFREE_ARRAY_AND_SET_TO_NULL( char, stringBufferSizeInclTermZero, ptr ) #define ELASTIC_APM_PEFREE_STRING_SIZE_AND_SET_TO_NULL( stringBufferSizeInclTermZero, ptr ) \ ELASTIC_APM_PEFREE_ARRAY_AND_SET_TO_NULL( char, stringBufferSizeInclTermZero, ptr ) #define ELASTIC_APM_EFREE_STRING_AND_SET_TO_NULL( ptr ) \ ELASTIC_APM_EFREE_STRING_SIZE_AND_SET_TO_NULL( ( (ptr) == NULL ) ? 0 : ( strlen( ptr ) + 1 ), ptr ) #define ELASTIC_APM_PEFREE_STRING_AND_SET_TO_NULL( ptr ) \ ELASTIC_APM_PEFREE_STRING_SIZE_AND_SET_TO_NULL( ( (ptr) == NULL ) ? 0 : ( strlen( ptr ) + 1 ), ptr ) #define ELASTIC_APM_MALLOC_IF_FAILED_DO_EX( type, requestedSizeInBytes, outPtr, doOnFailure ) \ do { \ void* mallocIfFailedDoExPtr = malloc( (requestedSizeInBytes) ); \ if ( mallocIfFailedDoExPtr == NULL ) \ { \ resultCode = resultOutOfMemory; \ doOnFailure; \ } \ (outPtr) = (type*)(mallocIfFailedDoExPtr); \ } while ( 0 ) #define ELASTIC_APM_MALLOC_IF_FAILED_GOTO( type, requestedSizeInBytes, outPtr ) \ ELASTIC_APM_MALLOC_IF_FAILED_DO_EX( type, requestedSizeInBytes, outPtr, /* doOnFailure: */ goto failure ) #define ELASTIC_APM_MALLOC_STRING_IF_FAILED_GOTO( maxLength, outPtr ) \ ELASTIC_APM_MALLOC_IF_FAILED_GOTO( char, sizeof( char ) * ((maxLength) + 1) /* <- +1 for terminating '\0' */, outPtr ) #define ELASTIC_APM_MALLOC_STRING_BUFFER_IF_FAILED_GOTO( maxLength, strBuf ) \ do { \ ELASTIC_APM_MALLOC_STRING_IF_FAILED_GOTO( (maxLength), /* outPtr */ (strBuf).begin ); \ (strBuf).size = (maxLength) + 1; \ } while ( 0 ) #define ELASTIC_APM_MALLOC_INSTANCE_IF_FAILED_GOTO( type, outPtr ) \ ELASTIC_APM_MALLOC_IF_FAILED_GOTO( type, sizeof( type ), outPtr ) #define ELASTIC_APM_FREE_AND_SET_TO_NULL( type, requestedSizeInBytes, ptr ) \ do { \ if ( (ptr) != NULL ) \ { \ free( (void*)(ptr) ); \ (ptr) = (type*)(NULL); \ } \ } while ( 0 ) #define ELASTIC_APM_FREE_INSTANCE_AND_SET_TO_NULL( type, ptr ) \ ELASTIC_APM_FREE_AND_SET_TO_NULL( type, sizeof( type ), ptr ) #define ELASTIC_APM_FREE_STRING_AND_SET_TO_NULL( maxLength, ptr ) \ ELASTIC_APM_FREE_AND_SET_TO_NULL( char, sizeof( char ) * ((maxLength) + 1) /* <- +1 for terminating '\0' */, ptr ) #define ELASTIC_APM_FREE_STRING_BUFFER_AND_SET_TO_NULL( strBuf ) \ do { \ if ( (strBuf).size != 0 ) \ { \ ELASTIC_APM_FREE_STRING_AND_SET_TO_NULL( /* maxLength */ (strBuf).size - 1, /* ptr */ (strBuf).begin ); \ (strBuf) = ELASTIC_APM_EMPTY_STRING_BUFFER; \ } \ } while ( 0 )