CRASH caused by unsafe C-style subclass cast in UCharacterMovementComponent::CapsuleTouched

Summary

I’m writing my own mesh component with Multiple BodyInstance and hit a crash in UCharacterMovementComponent::CapsuleTouched when enable Overlap for (Character Capsule ↔ my Component)

Though Stack I find a very dangerous C-style subclass cast in

	if (OtherBodyIndex != INDEX_NONE)
	{
		BoneName = ((USkinnedMeshComponent*)OtherComp)->GetBoneName(OtherBodyIndex);
	}

After some investigation, I find there also have several NOT SkinnedMeshComponent but that may have not INDEX_NONE BodyIndex, so simply change to safe Cast is not enough.

Other Components are:
UInstancedStaticMeshComponent
UGeometryCollectionComponent
also my comp UEdenRigidRopeComponent

So, that should be a general bug, I think make a virtual function for this or Use IPhysicsBodyInstanceOwner::GetBodyInstance is better.

(But if gonna use IPhysicsBodyInstanceOwner::GetBodyInstance also need some refactor since currently for USkeletalMeshComponent just ignore the Index Param)

What Type of Bug are you experiencing?

Gameplay

Steps to Reproduce

Use UE5.8, clone my example project

Open L_CapsuleTouchBug, Hit Play, should reproduce then

Expected Result

Not crash anymore, also provide virtual function is nessasary

Observed Result

Editor Crash

Affects Versions

5.8
5.7
5.6
5.5
5.4

Platform(s)

Android
iOS
Linux
Mac
OpenXR
visionOS
Windows

For crash reports, include your callstack

USkinnedMeshComponent::OutdatedKnownSkinnedAssetDetected'::2’::<lambda_1>::operator()() SkinnedMeshComponent.cpp:6050
USkinnedMeshComponent::OutdatedKnownSkinnedAssetDetected() SkinnedMeshComponent.cpp:6050
USkinnedMeshComponent::GetSkinnedAsset() SkinnedMeshComponent.cpp:2837
USkinnedMeshComponent::GetBoneName(int) SkinnedMeshComponent.cpp:2502
UCharacterMovementComponent::CapsuleTouched(UPrimitiveComponent *, AActor *, UPrimitiveComponent *, int, bool, const FHitResult &) CharacterMovementComponent.cpp:11694
UFunction::Invoke(UObject *, FFrame &, void *const) Class.cpp:7595
[Blueprint] CharacterMovementComponent: CapsuleTouched Function /Script/Engine.CharacterMovementComponent:CapsuleTouched
UObject::ProcessEvent(UFunction *, void *) ScriptCore.cpp:2232
[Inlined] TScriptDelegate::ProcessDelegate(void *) ScriptDelegates.h:1016
TMulticastScriptDelegate::ProcessDelegate<…>(void *) ScriptDelegates.h:1446
[Inlined] UE::Core::Private::TDelegateFunctionWrapper::CallWrapperImpl(const TDynamicMulticastDelegate<…> &, TIntegerSequence<…>, UPrimitiveComponent *, AActor *, UPrimitiveComponent *, int, bool, const FHitResult &) ScriptDelegates.h:454
[Inlined] UE::Core::Private::TDelegateFunctionWrapper::CallWrapper(const TDynamicMulticastDelegate<…> &, UPrimitiveComponent *, AActor *, UPrimitiveComponent *, int, bool, const FHitResult &) ScriptDelegates.h:478
[Inlined] TDynamicMulticastDelegate::Broadcast(UPrimitiveComponent *, AActor *, UPrimitiveComponent *, int, bool, const FHitResult &) DelegateSignatureImpl.inl:1504
TSparseDynamicDelegate::Broadcast<…>(UPrimitiveComponent *, AActor *, UPrimitiveComponent *, int, bool, FHitResult) SparseDelegate.h:333
UPrimitiveComponent::BeginComponentOverlap(const FOverlapInfo &, bool) PrimitiveComponent.cpp:4135
UPrimitiveComponent::UpdateOverlapsImpl(const TArrayView<…> *, bool, const TArrayView<…> *) PrimitiveComponent.cpp:4496
USceneComponent::UpdateOverlaps(const TArrayView<…> *, bool, const TArrayView<…> *) SceneComponent.cpp:1096
USceneComponent::EndScopedMovementUpdate(FScopedMovementUpdate &) SceneComponent.cpp:1307
FScopedMovementUpdate::~FScopedMovementUpdate() ScopedMovementUpdate.cpp:77
UCharacterMovementComponent::PerformMovement(float) CharacterMovementComponent.cpp:3105
UCharacterMovementComponent::ControlledCharacterMove(const UE::Math::TVector<…> &, float) CharacterMovementComponent.cpp:6457
UCharacterMovementComponent::TickComponent(float, ELevelTick, FActorComponentTickFunction *) CharacterMovementComponent.cpp:1757
[Inlined] FActorComponentTickFunction::ExecuteTick::l2::<lambda_1>::operator()(float) ActorComponent.cpp:1701
[Inlined] FActorComponentTickFunction::ExecuteTickHelper(UActorComponent *, bool, float, ELevelTick, const <lambda_1> &) Actor.h:4891
FActorComponentTickFunction::ExecuteTick(float, ELevelTick, Type, const TRefCountPtr<…> &) ActorComponent.cpp:1699
[Inlined] FTickFunctionTask::DoTask(Type, const TRefCountPtr<…> &) TickTaskManager.cpp:334
TGraphTask::ExecuteTask() TaskGraphInterfaces.h:703
UE::Tasks::Private::FTaskBase::TryExecuteTask() TaskPrivate.h:524
[Inlined] FBaseGraphTask::Execute(TArray<…> &, Type, bool) TaskGraphInterfaces.h:493
FNamedTaskThread::ProcessTasksNamedThread(int, bool) TaskGraph.cpp:807
FNamedTaskThread::ProcessTasksUntilIdle(int) TaskGraph.cpp:706
[Inlined] FTaskGraphCompatibilityImplementation::ProcessThreadUntilIdle(Type) TaskGraph.cpp:1447
FTaskGraphCompatibilityImplementation::ProcessUntilTasksComplete(const TArray<…> &, Type, const TFunction<…> &) TaskGraph.cpp:1585
FTickTaskSequencer::ReleaseTickGroup(ETickingGroup, bool, TArray<…> &) TickTaskManager.cpp:1040
FTickTaskManager::RunTickGroup(ETickingGroup, bool) TickTaskManager.cpp:2133
[Inlined] UWorld::RunTickGroup(ETickingGroup, bool) LevelTick.cpp:786
UWorld::Tick(ELevelTick, float) LevelTick.cpp:1750
UEditorEngine::Tick(float, bool) EditorEngine.cpp:2169
UUnrealEdEngine::Tick(float, bool) UnrealEdEngine.cpp:543
FEngineLoop::Tick() LaunchEngineLoop.cpp:5859
[Inlined] EngineTick() Launch.cpp:60
GuardedMain(const wchar_t *) Launch.cpp:192
LaunchWindowsStartup(HINSTANCE
*, HINSTANCE__ *, char *, int, const wchar_t *) LaunchWindows.cpp:266
WinMain(HINSTANCE__ *, HINSTANCE__ *, char *, int) LaunchWindows.cpp:338