/** * Captures the current stack and updates stack tracking information. * optionally stores a user data pointer that the tracker will take ownership of and delete upon reset * you must allocate the memory with FMemory::Malloc() */ void FStackTracker::CaptureStackTrace(int32 EntriesToIgnore /*=2*/, void* UserData /*=NULL*/) { // Avoid re-rentrancy as the code uses TArray/TMap. if( !bAvoidCapturing && bIsEnabled ) { // Scoped true/ false. bAvoidCapturing = true; // Capture callstack and create CRC. uint64* FullBackTrace = NULL; FullBackTrace = static_cast<uint64*>(FMemory_Alloca((MAX_BACKTRACE_DEPTH + EntriesToIgnore) * sizeof(uint64))); FPlatformStackWalk::CaptureStackBackTrace( FullBackTrace, MAX_BACKTRACE_DEPTH + EntriesToIgnore ); CA_ASSUME(FullBackTrace); // Skip first NUM_ENTRIES_TO_SKIP entries as they are inside this code uint64* BackTrace = &FullBackTrace[EntriesToIgnore]; uint32 CRC = FCrc::MemCrc_DEPRECATED( BackTrace, MAX_BACKTRACE_DEPTH * sizeof(uint64) ); // Use index if found int32* IndexPtr = CRCToCallStackIndexMap.Find( CRC ); if( IndexPtr ) { // Increase stack count for existing callstack. CallStacks[*IndexPtr].StackCount++; if (UpdateFn) { UpdateFn(CallStacks[*IndexPtr], UserData); } //We can delete this since the user gives ownership at the beginning of this call //and had a chance to update their data inside the above callback if (UserData) { FMemory::Free(UserData); } } // Encountered new call stack, add to array and set index mapping. else { // Add to array and set mapping for future use. int32 Index = CallStacks.AddUninitialized(); CRCToCallStackIndexMap.Add( CRC, Index ); // Fill in callstack and count. FCallStack& CallStack = CallStacks[Index]; FMemory::Memcpy( CallStack.Addresses, BackTrace, sizeof(uint64) * MAX_BACKTRACE_DEPTH ); CallStack.StackCount = 1; CallStack.UserData = UserData; } // We're done capturing. bAvoidCapturing = false; } }
void FJavaScriptHelper::ExecuteHook(UObject* Receiver, const FString& HookName, ICefRuntimeVariantList* Arguments) { UFunction* Function = Receiver->GetClass()->FindFunctionByName(*HookName); if (!Function) { UE_LOG(RadiantUILog, Error, TEXT("JavaScript Hook Function '%s' was not found"), *HookName); return; } int ArgumentMismatch = -1; if (Arguments) { if (Arguments->GetSize() != Function->NumParms) { UE_LOG(RadiantUILog, Error, TEXT("JavaScript Hook Function '%s' on Object '%s' was called with the wrong number arguments! The called function(called from JS) desires %i arguments, but the defined(in this game) has %i arguments."), *HookName, *Receiver->GetPathName(), Arguments->GetSize(), Function->NumParms); return; } void* Parms = (uint8*)FMemory_Alloca(Function->ParmsSize); FMemory::Memzero(Parms, Function->ParmsSize); int ArgumentIndex = 0; for (TFieldIterator<UProperty> It(Function); It && (It->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm; ++It, ++ArgumentIndex) { if (!StoreFunctionParameter(HookName, Parms, *It, Arguments->GetValue(ArgumentIndex), ArgumentIndex)) { return; } } Receiver->ProcessEvent(Function, Parms); } else { if (Function->NumParms == 0) { Receiver->ProcessEvent(Function, nullptr); } else { ArgumentMismatch = 0; } } if (ArgumentMismatch >= 0) { UE_LOG(RadiantUILog, Error, TEXT("JavaScript Hook Function '%s' argument %d type mismatch"), *HookName, ArgumentMismatch); } }
void FGenericPlatformMemory::Memswap( void* Ptr1, void* Ptr2, SIZE_T Size ) { if (Ptr1 != Ptr2) { // check that Ptr1 and Ptr2 do not overlap in undefined ways checkf(reinterpret_cast<uint8 *>(Ptr1)+Size <= reinterpret_cast<uint8 *>(Ptr2) || reinterpret_cast<uint8 *>(Ptr2)+Size <= reinterpret_cast<uint8 *>(Ptr1), TEXT("Pointers given to FPlatformMemory::Memswap() point to overlapping memory areas, results are undefined.")); void* Temp = FMemory_Alloca(Size); FPlatformMemory::Memcpy( Temp, Ptr1, Size ); FPlatformMemory::Memcpy( Ptr1, Ptr2, Size ); FPlatformMemory::Memcpy( Ptr2, Temp, Size ); } }
PyObject *py_ue_skeletal_mesh_get_raw_indices(ue_PyUObject *self, PyObject * args) { ue_py_check(self); int lod_index = 0; if (!PyArg_ParseTuple(args, "|i:skeletal_mesh_get_raw_indices", &lod_index)) return nullptr; USkeletalMesh *mesh = ue_py_check_type<USkeletalMesh>(self); if (!mesh) return PyErr_Format(PyExc_Exception, "uobject is not a USkeletalMesh"); #if ENGINE_MINOR_VERSION < 19 FSkeletalMeshResource *resource = mesh->GetImportedResource(); #else FSkeletalMeshModel *resource = mesh->GetImportedModel(); #endif if (lod_index < 0 || lod_index >= resource->LODModels.Num()) return PyErr_Format(PyExc_Exception, "invalid LOD index, must be between 0 and %d", resource->LODModels.Num() - 1); #if ENGINE_MINOR_VERSION < 19 FStaticLODModel &model = resource->LODModels[lod_index]; #else FSkeletalMeshLODModel &model = resource->LODModels[lod_index]; #endif PyObject *py_list = PyList_New(0); int32 *raw_indices = (int32 *)model.RawPointIndices.Lock(LOCK_READ_ONLY); int32 *indices = (int32 *)FMemory_Alloca(model.RawPointIndices.GetBulkDataSize()); FMemory::Memcpy(indices, raw_indices, model.RawPointIndices.GetBulkDataSize()); model.RawPointIndices.Unlock(); for (int32 index = 0; index < model.RawPointIndices.GetBulkDataSize() / sizeof(int32); index++) { PyList_Append(py_list, PyLong_FromLong(indices[index])); } return py_list; }
void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL) { FScopePythonGIL gil; UPythonFunction *function = static_cast<UPythonFunction *>(Stack.CurrentNativeFunction); bool on_error = false; bool is_static = function->HasAnyFunctionFlags(FUNC_Static); // count the number of arguments Py_ssize_t argn = (Stack.Object && !is_static) ? 1 : 0; TFieldIterator<UProperty> IArgs(function); for (; IArgs && ((IArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++IArgs) { argn++; } #if defined(UEPY_MEMORY_DEBUG) UE_LOG(LogPython, Warning, TEXT("Initializing %d parameters"), argn); #endif PyObject *py_args = PyTuple_New(argn); if (Stack.Object && !is_static) { PyObject *py_obj = (PyObject *)ue_get_python_wrapper(Stack.Object); if (!py_obj) { unreal_engine_py_log_error(); on_error = true; } else { Py_INCREF(py_obj); PyTuple_SetItem(py_args, 0, py_obj); } } uint8 *frame = Stack.Locals; argn = (Stack.Object && !is_static) ? 1 : 0; // is it a blueprint call ? if (*Stack.Code == EX_EndFunctionParms) { for (UProperty *prop = (UProperty *)function->Children; prop; prop = (UProperty *)prop->Next) { if (prop->PropertyFlags & CPF_ReturnParm) continue; if (!on_error) { PyObject *arg = ue_py_convert_property(prop, (uint8 *)Stack.Locals); if (!arg) { unreal_engine_py_log_error(); on_error = true; } else { PyTuple_SetItem(py_args, argn++, arg); } } } } else { //UE_LOG(LogPython, Warning, TEXT("BLUEPRINT CALL")); frame = (uint8 *)FMemory_Alloca(function->PropertiesSize); FMemory::Memzero(frame, function->PropertiesSize); for (UProperty *prop = (UProperty *)function->Children; *Stack.Code != EX_EndFunctionParms; prop = (UProperty *)prop->Next) { Stack.Step(Stack.Object, prop->ContainerPtrToValuePtr<uint8>(frame)); if (prop->PropertyFlags & CPF_ReturnParm) continue; if (!on_error) { PyObject *arg = ue_py_convert_property(prop, frame); if (!arg) { unreal_engine_py_log_error(); on_error = true; } else { PyTuple_SetItem(py_args, argn++, arg); } } } } Stack.Code++; if (on_error || !function->py_callable) { Py_DECREF(py_args); return; } PyObject *ret = PyObject_CallObject(function->py_callable, py_args); Py_DECREF(py_args); if (!ret) { unreal_engine_py_log_error(); return; } // get return value (if required) UProperty *return_property = function->GetReturnProperty(); if (return_property && function->ReturnValueOffset != MAX_uint16) { #if defined(UEPY_MEMORY_DEBUG) UE_LOG(LogPython, Warning, TEXT("FOUND RETURN VALUE")); #endif if (ue_py_convert_pyobject(ret, return_property, frame)) { // copy value to stack result value FMemory::Memcpy(RESULT_PARAM, frame + function->ReturnValueOffset, return_property->ArrayDim * return_property->ElementSize); } else { UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString()); } } Py_DECREF(ret); }
/** * Captures the current stack and updates stack tracking information. * optionally stores a user data pointer that the tracker will take ownership of and delete upon reset * you must allocate the memory with FMemory::Malloc() */ void FStackTracker::CaptureStackTrace(int32 EntriesToIgnore, void* UserData, int32 StackLen, bool bLookupStringsForAliasRemoval) { // Avoid re-rentrancy as the code uses TArray/TMap. if( !bAvoidCapturing && bIsEnabled ) { // Scoped true/ false. bAvoidCapturing = true; // Capture callstack and create CRC. int32 Size = (MAX_BACKTRACE_DEPTH + EntriesToIgnore) * sizeof(uint64); uint64* FullBackTrace = static_cast<uint64*>(FMemory_Alloca(Size)); FMemory::Memzero(FullBackTrace, Size); FPlatformStackWalk::CaptureStackBackTrace( FullBackTrace, MAX_BACKTRACE_DEPTH + EntriesToIgnore ); CA_ASSUME(FullBackTrace); // Skip first NUM_ENTRIES_TO_SKIP entries as they are inside this code uint64* BackTrace = &FullBackTrace[EntriesToIgnore]; if (StackLen < MAX_BACKTRACE_DEPTH) { FMemory::Memzero(BackTrace + StackLen, sizeof(uint64) * (MAX_BACKTRACE_DEPTH - StackLen)); } if (bLookupStringsForAliasRemoval) { for (int32 Index = 0; Index < StackLen; Index++) { if (BackTrace[Index]) { uint64* Existing = AliasMap.Find(BackTrace[Index]); if (Existing) { BackTrace[Index] = *Existing; } else { ANSICHAR AddressInformation[512]; AddressInformation[0] = 0; FPlatformStackWalk::ProgramCounterToHumanReadableString( 1, BackTrace[Index], AddressInformation, ARRAY_COUNT(AddressInformation)-1 ); FString Symbol(AddressInformation); int32 Spot = Symbol.Find(TEXT(" - ")); if (Spot != INDEX_NONE) { Symbol = Symbol.RightChop(Spot + 3); } Existing = StringAliasMap.Find(Symbol); if (Existing) { AliasMap.Add(BackTrace[Index], *Existing); BackTrace[Index] = *Existing; } else { AliasMap.Add(BackTrace[Index], BackTrace[Index]); StringAliasMap.Add(Symbol, BackTrace[Index]); } } } } } uint32 CRC = FCrc::MemCrc_DEPRECATED( BackTrace, MAX_BACKTRACE_DEPTH * sizeof(uint64) ); // Use index if found int32* IndexPtr = CRCToCallStackIndexMap.Find( CRC ); if( IndexPtr ) { // Increase stack count for existing callstack. CallStacks[*IndexPtr].StackCount++; if (UpdateFn) { UpdateFn(CallStacks[*IndexPtr], UserData); } //We can delete this since the user gives ownership at the beginning of this call //and had a chance to update their data inside the above callback if (UserData) { FMemory::Free(UserData); } } // Encountered new call stack, add to array and set index mapping. else { // Add to array and set mapping for future use. int32 Index = CallStacks.AddUninitialized(); CRCToCallStackIndexMap.Add( CRC, Index ); // Fill in callstack and count. FCallStack& CallStack = CallStacks[Index]; FMemory::Memcpy( CallStack.Addresses, BackTrace, sizeof(uint64) * MAX_BACKTRACE_DEPTH ); CallStack.StackCount = 1; CallStack.UserData = UserData; } // We're done capturing. bAvoidCapturing = false; } }