Pasting from the UDN:
Unsafe code in AbilitySystem can lead to crash when granting an ability inside OnAbilityEnded
Hello.
We just ran into a crash. After investigation, it seems to be caused by the UAbilitySystemComponent::NotifyAbilityEnded() function, when trying to access the Spec pointer at the end of the function.
The code inside the function seems a bit unsafe :
[Image Removed]
(1) We grab the Spec pointer from inside the ability array (1)
(2) Then we trigger the OnAbilityEnded delegate which can cause any gameplay code the happen. In our case we where granting and ability, which invalidate the Spec pointer when abilities array is updated.
(3) After than the Spec pointer is still accessed which leads to a crash.
Jodon's Note: Copying the Spec is probably not a valid solution because we want to remove the ReplicatedInstances later on from the actual original Spec.
Note that this will only occur when writing custom native code. Instead of doing a nice full-fledged example, I'm sticking the code in a bad, but easy-to-repro spot. This isn't "good coding" but you can at least reproduce the issue this way:
Add this near the bottom of ULyraAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor), right after TryActivateAbilitiesOnSpawn(); (but inside the if statement):
his->OnAbilityEnded.AddWeakLambda(this, [this](const FAbilityEndedData& AbilityEnded) { if (AbilityEnded.bWasCancelled) { return; } TArray<FGameplayAbilitySpecHandle> ActiveAbilities; GetAllAbilities(ActiveAbilities); // Cancel a random amount of abilities to try and show the calling function is unsafe for (const FGameplayAbilitySpecHandle& SpecHandle : ActiveAbilities) { if (FMath::RandBool()) { SetRemoveAbilityOnEnd(SpecHandle); ClearAbility(SpecHandle); break; } else if (FMath::RandBool()) { FGameplayAbilitySpec RegrantAbility{ AbilityEnded.AbilityThatEnded.GetClass() }; GiveAbilityAndActivateOnce(RegrantAbility); } } });
That will randomly remove/re-add abilities as you're completing them. The idea is that you want to cause reallocations of the ActivatableItems array while the Ability is ending to force a memory stomp.
With that code:
If it's still a bug, it will crash at some point (likely on access to invalid memory). If it's fixed it won't crash. Do it about 10 runs to be safe.
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-197731 in the post.
1 |
Component | UE - Gameplay - Gameplay Ability System |
---|---|
Affects Versions | 5.3 |
Target Fix | 5.4 |
Fix Commit | 29277076 |
---|---|
Main Commit | 29277145 |
Created | Oct 11, 2023 |
---|---|
Resolved | Nov 1, 2023 |
Updated | Dec 12, 2023 |