467 /// Even though [`SharedByPyObject`] tries to enforce the real lifetime of the |
467 /// Even though [`SharedByPyObject`] tries to enforce the real lifetime of the |
468 /// underlying object, the object having the artificial `'static` lifetime |
468 /// underlying object, the object having the artificial `'static` lifetime |
469 /// may be exposed to your Rust code. You must be careful to not make a bare |
469 /// may be exposed to your Rust code. You must be careful to not make a bare |
470 /// reference outlive the actual object lifetime. |
470 /// reference outlive the actual object lifetime. |
471 /// |
471 /// |
472 /// ```ignore |
472 /// See [`Self::try_borrow_mut()`] for an example of the kind of trouble that |
473 /// let mut outer = empty; |
473 /// can arise. |
474 /// let mut shared_iter = shared.map(py, |o| o.chars()); |
|
475 /// { |
|
476 /// let mut iter = unsafe { shared_iter.try_borrow_mut(py) }; |
|
477 /// let inner = iter.next(); // Good, in borrow scope |
|
478 /// outer = inner; // Bad, &'static T may outlive |
|
479 /// } |
|
480 /// ``` |
|
481 pub struct SharedByPyObject<T: ?Sized> { |
474 pub struct SharedByPyObject<T: ?Sized> { |
482 owner: PyObject, |
475 owner: PyObject, |
483 state: &'static PySharedState, |
476 state: &'static PySharedState, |
484 /// Generation counter of data `T` captured when SharedByPyObject is |
477 /// Generation counter of data `T` captured when SharedByPyObject is |
485 /// created. |
478 /// created. |
496 impl<T: ?Sized> SharedByPyObject<T> { |
489 impl<T: ?Sized> SharedByPyObject<T> { |
497 // No panicking version of borrow() and borrow_mut() are implemented |
490 // No panicking version of borrow() and borrow_mut() are implemented |
498 // because the underlying value is supposed to be mutated in Python |
491 // because the underlying value is supposed to be mutated in Python |
499 // world, and the Rust library designer can't prevent it. |
492 // world, and the Rust library designer can't prevent it. |
500 |
493 |
501 // try_borrow() and try_borrow_mut() are unsafe because self.data may |
|
502 // have a function returning the inner &'static reference. |
|
503 // If T is &'static U, its lifetime can be easily coerced to &'a U, but |
|
504 // how could we do that for Whatever<'static> in general? |
|
505 |
|
506 /// Immutably borrows the wrapped value. |
494 /// Immutably borrows the wrapped value. |
507 /// |
495 /// |
508 /// Borrowing fails if the underlying reference has been invalidated. |
496 /// Borrowing fails if the underlying reference has been invalidated. |
509 /// |
497 /// |
510 /// # Safety |
498 /// # Safety |
511 /// |
499 /// |
512 /// The lifetime of the innermost object is artificial. Do not obtain and |
500 /// The lifetime of the innermost object is artificial. Do not obtain and |
513 /// copy it out of the borrow scope. |
501 /// copy it out of the borrow scope. |
|
502 /// |
|
503 /// The lifetime of the innermost object is artificial. Do not obtain and |
|
504 /// copy it out of the borrow scope. More generally, the returned `&T` |
|
505 /// may have a method returning an inner reference, which would typically |
|
506 /// be `'static` and not safe without the `owner` Python object, so the |
|
507 /// problem might be less obvious than in the example below. |
|
508 /// |
|
509 /// The following example does compile and illustrates the problem. |
|
510 /// In this case, the data is a `Vec<String>` and the leaked reference |
|
511 /// `&'static str`, which points to some element of the vector. This |
|
512 /// illustrates that the leaks are not necessarily to the whole of the |
|
513 /// shared data. |
|
514 /// |
|
515 /// ```no_run |
|
516 /// # use pyo3::prelude::*; |
|
517 /// # use pyo3_sharedref::PyShareable; |
|
518 /// #[pyclass] |
|
519 /// struct Owner { |
|
520 /// value: PyShareable<Vec<String>> |
|
521 /// } |
|
522 /// |
|
523 /// #[pymethods] |
|
524 /// impl Owner { |
|
525 /// #[new] |
|
526 /// fn new(s: &str) -> Self { |
|
527 /// let split: Vec<_> = s.split(' ').map(String::from).collect(); |
|
528 /// Self { value: split.into() } |
|
529 /// } |
|
530 /// } |
|
531 /// |
|
532 /// const EMPTY: &'static str = ""; |
|
533 /// |
|
534 /// let mut outer = EMPTY; |
|
535 /// Python::with_gil(|py| { |
|
536 /// let owner = Bound::new(py, Owner::new("hello")).unwrap(); |
|
537 /// let shareable = &owner.borrow().value; |
|
538 /// let shared = unsafe { shareable.share(&owner) }; |
|
539 /// { |
|
540 /// let inner = unsafe { shared.try_borrow(py) }.unwrap(); |
|
541 /// outer = &inner[0]; // Bad, &'static str does outlive the scope |
|
542 /// } |
|
543 /// }); |
|
544 /// ``` |
514 pub unsafe fn try_borrow<'a>( |
545 pub unsafe fn try_borrow<'a>( |
515 &'a self, |
546 &'a self, |
516 py: Python<'a>, |
547 py: Python<'a>, |
517 ) -> PyResult<SharedByPyObjectRef<'a, T>> { |
548 ) -> PyResult<SharedByPyObjectRef<'a, T>> { |
518 self.validate_generation(py)?; |
549 self.validate_generation(py)?; |
524 |
555 |
525 /// Mutably borrows the wrapped value. |
556 /// Mutably borrows the wrapped value. |
526 /// |
557 /// |
527 /// Borrowing fails if the underlying reference has been invalidated. |
558 /// Borrowing fails if the underlying reference has been invalidated. |
528 /// |
559 /// |
529 /// Typically `T` is an iterator. If `T` is an immutable reference, |
560 /// Typically `T` would be an iterator obtained by the [`Self::map`] |
530 /// `get_mut()` is useless since the inner value can't be mutated. |
561 /// method. |
531 /// |
562 /// |
532 /// # Safety |
563 /// # Safety |
533 /// |
564 /// |
534 /// The lifetime of the innermost object is artificial. Do not obtain and |
565 /// The lifetime of the innermost object is artificial. Do not obtain and |
535 /// copy it out of the borrow scope. |
566 /// copy it out of the borrow scope. More generally, the returned `&T` |
|
567 /// may have a method returning an inner reference, which would typically |
|
568 /// be `'static` and not safe without the `owner` Python object, so the |
|
569 /// problem might be less obvious than in the example below. |
|
570 /// |
|
571 /// The following example does compile and illustrates the problem. |
|
572 /// It is very close to the example given in [`Self::try_borrow`] because |
|
573 /// the problem does not arise from the mutability of the reference |
|
574 /// returned by this function. |
|
575 /// |
|
576 /// In this case, the data is a `Vec<String>` and the leaked reference |
|
577 /// `&'static str`, which points to some element of the vector. This |
|
578 /// illustrates that the leaks are not necessarily to the whole of the |
|
579 /// shared data. |
|
580 /// |
|
581 /// ```no_run |
|
582 /// # use pyo3::prelude::*; |
|
583 /// # use pyo3_sharedref::PyShareable; |
|
584 /// #[pyclass] |
|
585 /// struct Owner { |
|
586 /// value: PyShareable<Vec<String>> |
|
587 /// } |
|
588 /// |
|
589 /// #[pymethods] |
|
590 /// impl Owner { |
|
591 /// #[new] |
|
592 /// fn new(s: &str) -> Self { |
|
593 /// let split: Vec<_> = s.split(' ').map(String::from).collect(); |
|
594 /// Self { value: split.into() } |
|
595 /// } |
|
596 /// } |
|
597 /// |
|
598 /// const EMPTY: &'static str = ""; |
|
599 /// |
|
600 /// let mut outer = EMPTY; |
|
601 /// Python::with_gil(|py| { |
|
602 /// let owner = Bound::new(py, Owner::new("hello")).unwrap(); |
|
603 /// let shareable = &owner.borrow().value; |
|
604 /// let shared = unsafe { shareable.share(&owner) }; |
|
605 /// let mut shared_iter = unsafe { shared.map(py, |o| o.iter()) }; |
|
606 /// { |
|
607 /// let mut iter = unsafe { |
|
608 /// shared_iter.try_borrow_mut(py) |
|
609 /// }.unwrap(); |
|
610 /// let inner = iter.next().unwrap(); // Good, in borrow scope |
|
611 /// outer = inner; // Bad, &'static str does outlive the scope |
|
612 /// } |
|
613 /// }); |
|
614 /// ``` |
536 pub unsafe fn try_borrow_mut<'a>( |
615 pub unsafe fn try_borrow_mut<'a>( |
537 &'a mut self, |
616 &'a mut self, |
538 py: Python<'a>, |
617 py: Python<'a>, |
539 ) -> PyResult<SharedByPyObjectRefMut<'a, T>> { |
618 ) -> PyResult<SharedByPyObjectRefMut<'a, T>> { |
540 self.validate_generation(py)?; |
619 self.validate_generation(py)?; |