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

Ensure Disposable.NULL always returns a new Disposable #11053

Conversation

colin-grant-work
Copy link
Contributor

@colin-grant-work colin-grant-work commented Apr 21, 2022

What it does

Because of the way DisposableCollections handle disposal of their members, it is unsafe to add Disposable.NULL to any disposable collection: doing so risks disposal of one collection marking another collection as disposed inappropriately. This PR adds a test showing the risk of Disposable.NULL and replaces Disposable.NULL throughout the framework with a new method Disposable.createNull, with a test to demonstrate that disposables created in that way are safe for use in DisposableCollections.

How to test

  1. Assert that the tests in disposable.spec.ts pass (and look correct)
  2. Check that changes other than disposable.ts and dispospable.spec.ts just replace Disposable.NULL with Disposable.createNull
  3. Check that no references to Disposable.NULL remain in the framework.
  4. Check that the application behaves as expected.

Review checklist

Reminder for reviewers

@colin-grant-work colin-grant-work added bug bugs found in the application core issues related to the core of the application labels Apr 21, 2022
@paul-marechal
Copy link
Member

Is this related to the fact that Disposable.NULL always returns the same disposable instance, and DisposableCollection is messing with the reference of disposables added to it?

@paul-marechal
Copy link
Member

paul-marechal commented Apr 21, 2022

I honestly dislike what's being done to disposable references in DisposableCollection: it mutates instances with a new dispose function, and then tries to revert it somehow. Instead we should consider the instances as managed by the collection and assume dispose will only be called once by the collection and no one else.

Anyway, I would propose two alternative changes:

  1. Make Disposable.NULL return new instances on each access: see playground.
  2. Make DisposableCollection aware of Disposable.NULL and ignore it when pushed to it.

Those alternatives both have the benefit of requiring no changes for downstream projects. WDYT?

@colin-grant-work
Copy link
Contributor Author

colin-grant-work commented Apr 21, 2022

Is this related to the fact that Disposable.NULL always returns the same disposable instance, and DisposableCollection is messing with the reference of disposables added to it?

Yes, exactly.

I honestly dislike what's being done to disposable references in DisposableCollection.

Yeah, it's certainly not ideal. I'm not exactly sure what system to put in its place: if the point of disposables is to avoid leaks, then having some mechanism for removing references to them that occur outside of the collection currently disposing of itself is probably correct - otherwise they're leaking - but it probably doesn't make sense to have two different collections that can both dispose of something the holder of the other collection might be depending on. So it would probably make sense to guarantee that no disposable is ever put in two disposable collections, but I'm not sure how frequently that's happening in the wild or how much fixing it would take to ensure it doesn't happen.

Anyway, I would propose two alternative changes:

  1. Make Disposable.NULL return new instances on each access: see playground.
  2. Make DisposableCollection aware of Disposable.NULL and ignore it when pushed to it.

Those alternatives both have the benefit of requiring no changes for downstream projects. WDYT?

I'm in favor of 1, though in general I'm not very fond of manual prototype manipulation. But as you say, it would avoid having adopters need to do anything.

@paul-marechal
Copy link
Member

paul-marechal commented Apr 21, 2022

So it would probably make sense to guarantee that no disposable is ever put in two disposable collections [...]

I don't see how to enforce that nicely, I have better hope with being careful with our references and not sharing them to multiple dependants that all will try to dispose the same instance. To me it sounds like a "double free" kind of issue. Where is Rust's borrow checker when we need it? :)

Let's go with my first proposed change, I don't like it either but you can add a comment mentioning how each access will return a new disposable instance (the jsdoc should go in the declared namespace?).

@colin-grant-work colin-grant-work changed the title Deprecate Disposable.NULL and replace with Disposable.createNull Ensure Disposable.NULL always returns a new Disposable Apr 21, 2022
Copy link
Member

@paul-marechal paul-marechal left a comment

Choose a reason for hiding this comment

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

LGTM

@colin-grant-work colin-grant-work merged commit 7ef8e9d into eclipse-theia:master Apr 22, 2022
@colin-grant-work colin-grant-work deleted the deprecation/disposable-null branch April 22, 2022 15:50
@colin-grant-work colin-grant-work added this to the 1.25.0 milestone Apr 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug bugs found in the application core issues related to the core of the application
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants