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

Don't use object pool for initialOldData, and properly recycle tempObject #5459

Merged
merged 1 commit into from
Feb 12, 2024

Conversation

mrxz
Copy link
Contributor

@mrxz mrxz commented Feb 11, 2024

Description:
A temporary object was never released to the objectPool, causing a leak. After fixing this leak, some unit tests regressed. It turns out that the initialOldData provided to a component's update(oldData) is also leased from this pool. The pool however makes no guarantees about the state of the object. It might very well not be an empty object. (And due to the various leaks, it likely was an empty object)

This PR correctly clears and returns the tempObject to the pool and uses a constant frozen empty object for the initialOldData. This is a slight change in behaviour in case users mutate this object, but that was never correct and will now give an error.

Changes proposed:

  • Correctly clear and recycle tempObject in Component update logic (updateCachedAttrValue)
  • No longer use object pool for initialOldData for a Component's first update call

@@ -203,6 +204,7 @@ Component.prototype = {
// If value is an object, copy it to our pooled newAttrValue object to use to update
// the attrValue.
tempObject = this.objectPool.use();
utils.objectPool.clearObject(tempObject);
Copy link
Member

Choose a reason for hiding this comment

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

So I understand. use function should already calls clearObject. Is not this redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, seems when cleaning up the PR I got clearObject and removeUnusedKeys mixed up in this place. The object pool does indeed "clear" the object, but the keys remains. Looking at the code again in more detail, it is actually safe here to have superfluous keys on tempObject in the subsequent utils.extend and extendProperties calls.

@@ -324,9 +326,8 @@ Component.prototype = {

// For oldData, pass empty object to multiple-prop schemas or object single-prop schema.
// Pass undefined to rest of types.
initialOldData = this.isObjectBased ? this.objectPool.use() : undefined;
initialOldData = this.isObjectBased ? emptyInitialOldData : undefined;
Copy link
Member

Choose a reason for hiding this comment

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

Same here. My understanding is that the use function calls clearObject. You mention

The pool however makes no guarantees about the state of the object. It might very well not be an empty object

What Am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem is that clearObject only sets the keys to undefined. As a result the initialOldData can have zero or more keys present. This means that any update code doing things like Object.keys(oldData) or "someProp" in oldData ends up getting incorrect results.

Before there was enough leakage that you'd generally always get a fresh empty object from the pool.

@mrxz mrxz force-pushed the fix-initial-old-data branch from 4308889 to a565ab3 Compare February 12, 2024 09:10
@dmarcos
Copy link
Member

dmarcos commented Feb 12, 2024

Thanks!

@dmarcos dmarcos merged commit 90c6936 into aframevr:master Feb 12, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants