From 1ffe3453cb2bd4cc031b4f8a4bdb88279e01e094 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Mon, 20 Jul 2015 16:57:29 -0700 Subject: [PATCH] make Rc mem::forget safe --- src/liballoc/rc.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d461eeea0b7..3eaffa1e028 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -160,7 +160,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{Hasher, Hash}; -use core::intrinsics::{assume, drop_in_place}; +use core::intrinsics::{assume, drop_in_place, abort}; use core::marker::{self, Unsize}; use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget}; use core::nonzero::NonZero; @@ -846,6 +846,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +// NOTE: We checked_add here to deal with mem::forget safety. In particular +// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then +// you can free the allocation while outstanding Rcs (or Weaks) exist. +// We abort because this is such a degenerate scenario that we don't care about +// what happens -- no real program should ever experience this. +// +// This should have negligible overhead since you don't actually need to +// clone these much in Rust thanks to ownership and move-semantics. + #[doc(hidden)] trait RcBoxPtr { fn inner(&self) -> &RcBox; @@ -854,7 +863,9 @@ trait RcBoxPtr { fn strong(&self) -> usize { self.inner().strong.get() } #[inline] - fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + fn inc_strong(&self) { + self.inner().strong.set(self.strong().checked_add(1).unwrap_or_else(|| unsafe { abort() })); + } #[inline] fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } @@ -863,7 +874,9 @@ fn strong(&self) -> usize { self.inner().strong.get() } fn weak(&self) -> usize { self.inner().weak.get() } #[inline] - fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } + fn inc_weak(&self) { + self.inner().weak.set(self.weak().checked_add(1).unwrap_or_else(|| unsafe { abort() })); + } #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } -- 2.44.0