-
Notifications
You must be signed in to change notification settings - Fork 12
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
Audit updateDisplay() for side effects that effect the Node scene graph state #1615
Comments
This seems important but I don't understand the problem yet and usages in |
Our investigation started by looking at usages of
More discussion:
Next steps:
@zepumph will take care of all items, and @jonathanolson will be assigned that separate issue. |
Here is a patch where we add a listener to the Node's disposal to update the Subject: [PATCH] Indicate that items have been sorted, see https://github.com/phetsims/scenery-phet/issues/815
---
Index: js/accessibility/FocusDisplayedController.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/accessibility/FocusDisplayedController.ts b/js/accessibility/FocusDisplayedController.ts
--- a/js/accessibility/FocusDisplayedController.ts (revision bfee694e3542ba44fa5bbb7f4ccd556ac038d292)
+++ b/js/accessibility/FocusDisplayedController.ts (date 1710350416893)
@@ -1,4 +1,4 @@
-// Copyright 2021-2024, University of Colorado Boulder
+// Copyright 2021-2023, University of Colorado Boulder
/**
* Responsible for setting the provided focusProperty to null when the Focused node either
@@ -22,11 +22,12 @@
private visibilityTracker: TrailVisibilityTracker | null = null;
// When there is value, we will watch and update when there are changes to the displayed state of the Focus trail.
- private focusProperty: TProperty<Focus | null> | null;
+ private focusProperty: TProperty<Focus | null>;
// Bound functions that are called when the displayed state of the Node changes.
private readonly boundVisibilityListener: () => void;
private readonly boundInstancesChangedListener: ( instance: Instance ) => void;
+ private readonly boundNodeDisposedListener: () => void;
// Handles changes to focus, adding or removing listeners
private readonly boundFocusListener: ( focus: Focus | null ) => void;
@@ -36,6 +37,7 @@
this.boundVisibilityListener = this.handleTrailVisibilityChange.bind( this );
this.boundInstancesChangedListener = this.handleInstancesChange.bind( this );
+ this.boundNodeDisposedListener = this.handleNodeDisposed.bind( this );
this.boundFocusListener = this.handleFocusChange.bind( this );
this.focusProperty.link( this.boundFocusListener );
@@ -58,7 +60,7 @@
*/
private handleTrailVisibilityChange(): void {
if ( this.visibilityTracker && !this.visibilityTracker.trailVisibleProperty.value ) {
- this.focusProperty!.value = null;
+ this.focusProperty.value = null;
}
}
@@ -68,9 +70,16 @@
*/
private handleInstancesChange( instance: Instance ): void {
if ( instance.node && instance.node.instances.length === 0 ) {
- this.focusProperty!.value = null;
+ this.focusProperty.value = null;
}
}
+
+ /**
+ *
+ */
+ private handleNodeDisposed(): void {
+ this.focusProperty.value = null;
+ }
/**
* Add listeners that watch when the Displayed state of the Node with Focus has changed,
@@ -85,6 +94,7 @@
this.node = focus.trail.lastNode();
this.node.changedInstanceEmitter.addListener( this.boundInstancesChangedListener );
+ this.node.disposeEmitter.addListener( this.boundNodeDisposedListener );
}
/**
@@ -99,6 +109,7 @@
}
if ( this.node ) {
this.node.changedInstanceEmitter.removeListener( this.boundInstancesChangedListener );
+ this.node.disposeEmitter.removeListener( this.boundNodeDisposedListener );
this.node = null;
}
}
@@ -107,11 +118,10 @@
// this disposes the TrailVisibilityTracker and removes any listeners on the Node
this.removeDisplayedListeners();
- this.focusProperty!.unlink( this.boundFocusListener );
+ this.focusProperty.unlink( this.boundFocusListener );
this.node = null;
this.visibilityTracker = null;
- this.focusProperty = null;
}
}
|
Side issues have been created. All that is left here is the above patch, and documentation updates (2 and 3 bullets above). |
When I removed the workaround, prior to applying the patch, I wasn't able to reproduce the problem, so I'll need to come back to this. |
…ty-buoyancy-common#97 Signed-off-by: Michael Kauzmann <[email protected]>
After much more fuzzing today, I could still not reproduce the bug, so I decided to commit the changes. I will monitor CT over in phetsims/density-buoyancy-common#97 to see if my new assertion (replacing the original workaround) is ever triggered. I will update documentation from here. |
Signed-off-by: Michael Kauzmann <[email protected]>
Alright. All remaining work here will be done in side issue. Thanks all! |
While working on phetsims/density-buoyancy-common#97 (comment), @jonathanolson mentioned that it is incredibly scary to be listening to
Node.changedInstanceEmitter
from spots that may effect the state of the scene graph. The three usages that we briefly looked at are all inscenery/js/accessibility
.The bug we ran into over in DBC was awkward because it involved a Property pointing to a Node that had been disposed, but the Property was set up to clear the disposed node correctly, just when the instances changed on updateDisplay. Fuzzing exposed this problem because of the input events occurring after the node was disposed, but before the frame ended.
Next steps to me are to understand the problem better. Most likely this means a conversation with @jonathanolson and @jessegreenberg. I'd also like to see some assertions put in place (even if under assert slow) that demonstrate when or where updateDisplay produces these side effects. Maybe not to commit, but at least to discuss. I'll mark as a high priority until I have a better understanding of the issue. Anyone feel free to change it.
The text was updated successfully, but these errors were encountered: