Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a NRE in DeliverUnit.ReleaseUnit.OnFirstRun #19587

Merged
merged 1 commit into from
Oct 2, 2021

Conversation

abcdefg30
Copy link
Member

Closes #19279.

@abcdefg30 abcdefg30 added this to the Next release milestone Aug 4, 2021
@pchote
Copy link
Member

pchote commented Aug 7, 2021

How does that happen in practice?

Mailaender
Mailaender previously approved these changes Sep 17, 2021
Copy link
Member

@Mailaender Mailaender left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense that this could be null. self would probably crash due to being dead.

@pchote
Copy link
Member

pchote commented Sep 20, 2021

Checking the source replay confirmed my suspicion that something more subtle was happing there.

The problem is that actors may run their activity in the time after being killed but before the end-tick disposal cleanup happening (IsDead: true, WillDispose: true, Disposed: false). The carryall (ActorID 900) is killed at the start of the tick, and its death handler disposes Carryable and sets it to null. The activity then runs and crashes due to the null actor.

We have two options here:

  1. Keep the DeliverUnit null check, but change the comment to explain this behaviour - this does fix the specific crash, but won't help with any other crashes of this type that haven't been discovered yet.
  2. Add a more general if (WillDispose) return in Actor.Tick - this is a more general fix, but might cause regressions if we have any code that relied on activities ticking while being disposed.

@abcdefg30
Copy link
Member Author

Updated as discussed on Discord (second push; first is a rebase): We go with 1) for now and do 2) for next+1.

@pchote pchote merged commit dc11b82 into OpenRA:bleed Oct 2, 2021
@abcdefg30 abcdefg30 deleted the releaseNull branch October 2, 2021 21:02
@reaperrr
Copy link
Contributor

reaperrr commented Oct 2, 2021

The problem is that actors may run their activity in the time after being killed but before the end-tick disposal cleanup happening (IsDead: true, WillDispose: true, Disposed: false). The carryall (ActorID 900) is killed at the start of the tick, and its death handler disposes Carryable and sets it to null. The activity then runs and crashes due to the null actor.

As far as I can tell, the problem is that player interfaces like INotifyWinStateChanged.OnPlayerLost don't adhere to the implicit order that the simulation code is designed around (activities -> traits -> effects), messing up the order in which the simulation code would expect things to happen. For example by triggering INotifyOwnerLost.OnOwnerLost in OwnerLostAction before any of the activities or regular trait stuff happens.

In my opinion the most robust fix would be to simply not allow killing actors before Actor.Tick() at all. OwnerLostAction and comparable traits that implement player interfaces probably should not directly affect actors until ITick.Tick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NRE in DeliverUnit.ReleaseUnit after player surrendered
4 participants