I’m creating a photography game. When the player raises the camera, they can take a picture and the last picture taken is displayed in a widget in the corner of the screen. Sometimes the game/editor will crash when raising the camera after at least one picture has been taken. Here is the crash report:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION 0x0000000000000000
UnrealEditor_Engine!FUniformExpressionSet::FillUniformBuffer() [D:\build++UE5\Sync\Engine\Source\Runtime\Engine\Private\Materials\MaterialUniformExpressions.cpp:936]
UnrealEditor_Engine!<lambda_25add83bda8d5688509793822c85efe4>::operator()() [D:\build++UE5\Sync\Engine\Source\Runtime\Engine\Private\Materials\MaterialShared.cpp:3865]
UnrealEditor_Engine!TGraphTask<TFunctionGraphTaskImpl<void __cdecl(void),0> >::ExecuteTask() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Async\TaskGraphInterfaces.h:1348]
UnrealEditor_Core!<lambda_13c427d0bfcf321a066cb5a2badfbc27>::operator()() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\Async\TaskGraph.cpp:2051]
UnrealEditor_Core!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<<lambda_17c904c32264d0348d15245fba0e1bff>,0>::CallAndMove() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Async\Fundamental\TaskDelegate.h:171]
UnrealEditor_Core!LowLevelTasks::FTask::ExecuteTask() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Async\Fundamental\Task.h:656]
UnrealEditor_Core!LowLevelTasks::FScheduler::ExecuteTask() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\Async\Fundamental\Scheduler.cpp:162]
UnrealEditor_Core!LowLevelTasks::FScheduler::TryExecuteTaskFrom<&LowLevelTasks::TLocalQueueRegistry<1024>::TLocalQueue::DequeueGlobal,0>() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\Async\Fundamental\Scheduler.cpp:361]
UnrealEditor_Core!LowLevelTasks::FScheduler::WorkerMain() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\Async\Fundamental\Scheduler.cpp:402]
UnrealEditor_Core!UE::Core::Private::Function::TFunctionRefCaller<<lambda_0a548c7e497de3cc77a9e48080e1524f>,void __cdecl(void)>::Call() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Templates\Function.h:475]
UnrealEditor_Core!FThreadImpl::Run() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\HAL\Thread.cpp:67]
UnrealEditor_Core!FRunnableThreadWin::Run() [D:\build++UE5\Sync\Engine\Source\Runtime\Core\Private\Windows\WindowsRunnableThread.cpp:149]
None of my code is shown in the crash log, but I believe I know the function that is leading to the crash. Here is the engine code where the crash is occurring (I’ve marked the precise line with “@CRASH”):
//...
const UTexture* Value = nullptr;
GetTextureValue(EMaterialTextureParameterType::Standard2D, ExpressionIndex, MaterialRenderContext,MaterialRenderContext.Material,Value);
if (Value)
{
// Pre-application validity checks (explicit ensures to avoid needless string allocation)
//const FMaterialUniformExpressionTextureParameter* TextureParameter = (Uniform2DTextureExpressions[ExpressionIndex]->GetType() == &FMaterialUniformExpressionTextureParameter::StaticType) ?
// &static_cast<const FMaterialUniformExpressionTextureParameter&>(*Uniform2DTextureExpressions[ExpressionIndex]) : nullptr;
// gmartin: Trying to locate UE-23902
if (!Value->IsValidLowLevel())
{
ensureMsgf(false, TEXT("Texture not valid! UE-23902! Parameter (%s)"), *Parameter.ParameterInfo.Name.ToString());
}
// Trying to track down a dangling pointer bug.
checkf(
Value->IsA<UTexture>(),
TEXT("Expecting a UTexture! Name(%s), Type(%s), TextureParameter(%s), Expression(%d), Material(%s)"),
*Value->GetName(), *Value->GetClass()->GetName(),
*Parameter.ParameterInfo.Name.ToString(),
ExpressionIndex,
*MaterialRenderContext.Material.GetFriendlyName());
// Do not allow external textures to be applied to normal texture samplers
if (Value->GetMaterialType() == MCT_TextureExternal) // @CRASH
{
FText MessageText = FText::Format(
NSLOCTEXT("MaterialExpressions", "IncompatibleExternalTexture", " applied to a non-external Texture2D sampler. This may work by chance on some platforms but is not portable. Please change sampler type to 'External'. Parameter '{0}' (slot {1}) in material '{2}'"),
FText::FromName(Parameter.ParameterInfo.GetName()),
ExpressionIndex,
FText::FromString(*MaterialRenderContext.Material.GetFriendlyName()));
GLog->Logf(ELogVerbosity::Warning, TEXT("%s"), *MessageText.ToString());
}
}
//...
I looked up the issue tracker tag referenced there (UE-23902), but it seems to be related to a crash caused by the CreateUniformBuffer method in the same file and is marked as fixed.
Here is the relevant code from my end that I believe is leading to the crash:
// Called with argument true each time the camera is raised, which is when the crash occurs:
void APhotoCameraEquipment::DisplayCameraHUD(bool bDisplay)
{
if (bDisplay)
{
UGameInstance* GameInstance = GetGameInstance();
CameraHUD = CreateWidget<UUserWidget>(GameInstance, CameraHUDClass, TEXT("CameraHUD"));
if (CameraHUD != nullptr && !CameraHUD->IsInViewport())
{
CameraHUD->AddToViewport();
LastPhotoImageWidget = CameraHUD->WidgetTree->FindWidget<UImage>(TEXT("LastPhotoImage"));
DisplayLastPhoto();
}
}
else
{
if (CameraHUD != nullptr && CameraHUD->IsInViewport()) {CameraHUD->RemoveFromParent();}
}
}
void APhotoCameraEquipment::DisplayLastPhoto()
{
FPhotoData LastPhoto = GetLastPhoto();
UTextureRenderTarget2D* PhotoImage = LastPhoto.Image;
if (LastPhotoImageWidget == nullptr) {return;}
UMaterialInstanceDynamic* PhotoRenderMat = LastPhotoImageWidget->GetDynamicMaterial();
if (PhotoRenderMat == nullptr || PhotoImage == nullptr) {return;}
PhotoRenderMat->SetTextureParameterValue(TEXT("PhotoRender"), PhotoImage);
FVector2D DisplaySize = FVector2D(PhotoImage->SizeX/10, PhotoImage->SizeY/10);
LastPhotoImageWidget->SetDesiredSizeOverride(DisplaySize);
LastPhotoImageWidget->SetVisibility(ESlateVisibility::Visible);
LogPhotoData(LastPhoto);
}
FPhotoData APhotoCameraEquipment::GetLastPhoto()
{
if (Photos.IsEmpty()) {return FPhotoData();}
return Photos[Photos.Num() - 1];
}
void APhotoCameraEquipment::LogPhotoData(FPhotoData Photo)
{
FString PhotoString = FString::Printf(TEXT("Photo taken at %s:\nSubjects: "), *(Photo.TimeTaken.ToString()));
float Score = 0;
for (FPhotoSubjectData Subject : Photo.Subjects)
{
PhotoString.Append(Subject.Name.ToString());
PhotoString.Append(FString(" | "));
for (FPhotoSubjectPointOfInterest PointOfInterest : Subject.PointsOfInterest)
{
if (PointOfInterest.IsVisible()) {Score += PointOfInterest.ScoreValue;}
}
}
PhotoString.Append(FString::Printf(TEXT("\nTotal Score: %f"), Score));
UE_LOG(LogTemp, Warning, TEXT("%s"), *PhotoString);
}
I don’t exactly know if the fault for the crash lies with my code or the engine, but the fact that it seems fairly random, paired with all of the references to threads and async tasks in the crash report makes me think it’s due to some race condition in the engine itself. I’m not sure if I should spend time trying to track it down, or if I should just update the engine and hope that A, the bug is fixed, and B, updating doesn’t break anything else in my project.