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(tauri): fix use-after-free unsoundness for state manager #12745

Closed
wants to merge 1 commit into from

Conversation

WSH032
Copy link
Contributor

@WSH032 WSH032 commented Feb 20, 2025

close #12721

another impl to #12723

@WSH032 WSH032 requested a review from a team as a code owner February 20, 2025 03:30
@WSH032
Copy link
Contributor Author

WSH032 commented Feb 20, 2025

ping @amrbashir

Comment on lines +45 to +54
#[deprecated(
since = "2.3.0",
note = "will cause memory leak, use `into_inner` or `Deref::deref` instead"
)]
pub fn inner(&self) -> &'r T {
let ptr = Arc::into_raw(self.0.clone());
// SAFETY: this ptr is valid, because we just created it;
// and the lifetime is 'static (it's leaked), so it's safe to return it.
unsafe { &*ptr }
}
Copy link
Member

Choose a reason for hiding this comment

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

a simple fix for this would be

 pub fn inner(&'r self) -> &'r T {
   self.0.as_ref()
 }

In normal cases, this should be a breaking change but since this fixes a memory leak, it should be fine

Copy link
Contributor Author

@WSH032 WSH032 Feb 20, 2025

Choose a reason for hiding this comment

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

I personally believe that most people do not need the unmanage feature (it seems that tauri itself does not use it also); if users really need unmanage, they can implement it themselves using Mutex and Option::take. This way, users who do not need mutability (unmanage) do not have to pay the performance cost (use Arc instead of Box, and Arc::clone for every get).

So, does tauri really want to introduce a BREAKING CHANGE in 2.x for this? Moreover, this BREAKING CHANGE would make pub fn inner(&'r self) -> &'r T quite useless (almost equivalent to removing it).

Copy link
Member

Choose a reason for hiding this comment

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

I assume you mean app.state().inner() use-case won't work? in that case I guess your solution is correct, and deref should be used instead.

Copy link
Contributor Author

@WSH032 WSH032 Feb 20, 2025

Choose a reason for hiding this comment

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

Here is my use case for fn inner: https://github.com/WSH032/pytauri/blob/47fe27d6f67c6d490ce753ac7976eb4b8a43cbdd/crates/tauri-plugin-pytauri/src/lib.rs#L103-L109.

With fn inner<'a>(&'a self) -> &'r T, I can return a reference of another type without needing to continue holding State.

If we really want to proceed as mentioned above, we might need to provide a method similar to MutexGuard::map to help convert State<'_, T> to State<'_, U>.

Copy link
Member

@amrbashir amrbashir Feb 20, 2025

Choose a reason for hiding this comment

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

at this point, I would go with #12723 for now, but instead of completely removing, we just document its pitfall and maybe print a warning in debug builds.

then in v3, we rework the API and introduce .map and remove inner in favor of deref

};

use crate::{
ipc::{CommandArg, CommandItem, InvokeError},
Runtime,
};

type Wrapper<T> = Arc<T>;
Copy link
Member

Choose a reason for hiding this comment

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

This just makes it confusing, let's remove and use Arc directly

type_id,
// SAFETY: keep the type of the key is the same as the type of the value,
// see following methods for details.
Box::new(Wrapper::new(state)) as Box<dyn Any + Sync + Send>,
Copy link
Member

Choose a reason for hiding this comment

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

we could remove Box and use Arc directly, should avoid a level of indirection

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.

[bug] StateManager is unsound
2 participants