{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/comments/33613031","id":33613031,"diff_hunk":"@@ -361,33 +334,114 @@ impl<T: Clone> Arc<T> {\n     /// # #![feature(arc_unique)]\n     /// use std::sync::Arc;\n     ///\n-    /// # unsafe {\n     /// let mut five = Arc::new(5);\n     ///\n     /// let mut_five = five.make_unique();\n-    /// # }\n     /// ```\n     #[inline]\n     #[unstable(feature = \"arc_unique\")]\n-    #[deprecated(since = \"1.2.0\",\n-                 reason = \"this function is unsafe with weak pointers\")]\n-    pub unsafe fn make_unique(&mut self) -> &mut T {\n-        // FIXME(#24880) potential race with upgraded weak pointers here\n-        //\n-        // Note that we hold a strong reference, which also counts as a weak\n-        // reference, so we only clone if there is an additional reference of\n-        // either kind.\n-        if self.inner().strong.load(SeqCst) != 1 ||\n-           self.inner().weak.load(SeqCst) != 1 {\n-            *self = Arc::new((**self).clone())\n+    pub fn make_unique(this: &mut Arc<T>) -> &mut T {\n+        // Note that we hold both a strong reference and a weak reference.\n+        // Thus, releasing our strong reference only will not, by itself, cause\n+        // the memory to be deallocated.\n+        if this.inner().strong.compare_and_swap(1, 0, Release) != 1 {\n+            // Another srong pointer exists; clone\n+            *this = Arc::new((**this).clone());\n+        } else if this.inner().weak.load(SeqCst) != 1 {\n+            // We removed the last strong ref, but there are additional weak\n+            // refs remaining. We'll move the contents to a new Arc, and\n+            // invalidate the other weak refs.\n+\n+            // Note that it is not possible for the read of `weak` to yield\n+            // usize::MAX (i.e., locked), since the weak count can only be\n+            // locked by a thread with a strong reference.\n+\n+            // Materializae our own implicit weak pointer, so that it can clean\n+            // up the ArcInner as needed.\n+            let weak = Weak { _ptr: this._ptr };\n+            // mark the data itself as already deallocated\n+            this._ptr = unsafe { NonZero::new(0 as *mut _) };\n+            unsafe {\n+                *this = Arc::new(ptr::read(&(**weak._ptr).data));\n+            }\n+        } else {\n+            // We were the sole reference of either kind; bump back up the\n+            // strong ref count.\n+            this.inner().strong.store(1, Release);\n         }\n+\n         // As with `get_mut()`, the unsafety is ok because our reference was\n         // either unique to begin with, or became one upon cloning the contents.\n-        let inner = &mut **self._ptr;\n-        &mut inner.data\n+        unsafe {\n+            let inner = &mut **this._ptr;\n+            &mut inner.data\n+        }\n     }\n }\n \n+impl<T: ?Sized> Arc<T> {\n+    /// Returns a mutable reference to the contained value if the `Arc<T>` is unique.\n+    ///\n+    /// Returns `None` if the `Arc<T>` is not unique.\n+    ///\n+    /// # Examples\n+    ///\n+    /// ```\n+    /// # #![feature(arc_unique, alloc)]\n+    /// extern crate alloc;\n+    /// # fn main() {\n+    /// use alloc::arc::{Arc, get_mut};\n+    ///\n+    /// let mut x = Arc::new(3);\n+    /// *get_mut(&mut x).unwrap() = 4;\n+    /// assert_eq!(*x, 4);\n+    ///\n+    /// let _y = x.clone();\n+    /// assert!(get_mut(&mut x).is_none());\n+    /// # }\n+    /// ```\n+    #[inline]\n+    #[unstable(feature = \"arc_unique\")]\n+    pub fn get_mut(this: &mut Arc<T>) -> Option<&mut T> {","path":"src/liballoc/arc.rs","position":207,"original_position":207,"commit_id":"d264b0e0a2ddd5dcde998c10bb2f677fe2a35a2a","original_commit_id":"d264b0e0a2ddd5dcde998c10bb2f677fe2a35a2a","user":{"login":"nagisa","id":679122,"avatar_url":"https://avatars.githubusercontent.com/u/679122?v=3","gravatar_id":"","url":"https://api.github.com/users/nagisa","html_url":"https://github.com/nagisa","followers_url":"https://api.github.com/users/nagisa/followers","following_url":"https://api.github.com/users/nagisa/following{/other_user}","gists_url":"https://api.github.com/users/nagisa/gists{/gist_id}","starred_url":"https://api.github.com/users/nagisa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nagisa/subscriptions","organizations_url":"https://api.github.com/users/nagisa/orgs","repos_url":"https://api.github.com/users/nagisa/repos","events_url":"https://api.github.com/users/nagisa/events{/privacy}","received_events_url":"https://api.github.com/users/nagisa/received_events","type":"User","site_admin":false},"body":"I don’t see how that’s a problem given we have UFCS.","created_at":"2015-06-30T19:24:23Z","updated_at":"2015-06-30T19:24:23Z","html_url":"https://github.com/rust-lang/rust/pull/26610#discussion_r33613031","pull_request_url":"https://api.github.com/repos/rust-lang/rust/pulls/26610","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments/33613031"},"html":{"href":"https://github.com/rust-lang/rust/pull/26610#discussion_r33613031"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/26610"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/26610","id":38694004,"html_url":"https://github.com/rust-lang/rust/pull/26610","diff_url":"https://github.com/rust-lang/rust/pull/26610.diff","patch_url":"https://github.com/rust-lang/rust/pull/26610.patch","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/26610","number":26610,"state":"open","locked":false,"title":"Fix race condition in Arc's get_mut and make_unqiue","user":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"body":"This commit resolves the race condition in the `get_mut` and\r\n`make_unique` functions, which arose through interaction with weak\r\npointers. The basic strategy is to \"lock\" the weak pointer count when\r\ntrying to establish uniqueness, by reusing the field as a simple\r\nspinlock. The overhead for normal use of `Arc` is expected to be minimal\r\n-- it will be *none* when only strong pointers are used, and only\r\nrequires a move from atomic increment to CAS for usage of weak pointers.\r\n\r\nThe commit also removes the `unsafe` and deprecated status of these functions.\r\n\r\nCloses #24880\r\n\r\nr? @alexcrichton \r\n\r\ncc @metajack @SimonSapin @Ms2ger ","created_at":"2015-06-26T22:08:23Z","updated_at":"2015-06-30T19:24:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"38124e295f788495a2a8be58abe1ffa753cb6eb4","assignee":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rust/pulls/26610/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rust/pulls/26610/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rust/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/26610/comments","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/d264b0e0a2ddd5dcde998c10bb2f677fe2a35a2a","head":{"label":"aturon:fix_make_unique","ref":"fix_make_unique","sha":"d264b0e0a2ddd5dcde998c10bb2f677fe2a35a2a","user":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"repo":{"id":19056749,"name":"rust","full_name":"aturon/rust","owner":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aturon/rust","description":"a safe, concurrent, practical language","fork":true,"url":"https://api.github.com/repos/aturon/rust","forks_url":"https://api.github.com/repos/aturon/rust/forks","keys_url":"https://api.github.com/repos/aturon/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aturon/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aturon/rust/teams","hooks_url":"https://api.github.com/repos/aturon/rust/hooks","issue_events_url":"https://api.github.com/repos/aturon/rust/issues/events{/number}","events_url":"https://api.github.com/repos/aturon/rust/events","assignees_url":"https://api.github.com/repos/aturon/rust/assignees{/user}","branches_url":"https://api.github.com/repos/aturon/rust/branches{/branch}","tags_url":"https://api.github.com/repos/aturon/rust/tags","blobs_url":"https://api.github.com/repos/aturon/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aturon/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aturon/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/aturon/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aturon/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/aturon/rust/languages","stargazers_url":"https://api.github.com/repos/aturon/rust/stargazers","contributors_url":"https://api.github.com/repos/aturon/rust/contributors","subscribers_url":"https://api.github.com/repos/aturon/rust/subscribers","subscription_url":"https://api.github.com/repos/aturon/rust/subscription","commits_url":"https://api.github.com/repos/aturon/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/aturon/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/aturon/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/aturon/rust/issues/comments{/number}","contents_url":"https://api.github.com/repos/aturon/rust/contents/{+path}","compare_url":"https://api.github.com/repos/aturon/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aturon/rust/merges","archive_url":"https://api.github.com/repos/aturon/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aturon/rust/downloads","issues_url":"https://api.github.com/repos/aturon/rust/issues{/number}","pulls_url":"https://api.github.com/repos/aturon/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/aturon/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/aturon/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aturon/rust/labels{/name}","releases_url":"https://api.github.com/repos/aturon/rust/releases{/id}","created_at":"2014-04-23T04:19:14Z","updated_at":"2014-06-21T05:46:22Z","pushed_at":"2015-06-30T17:43:20Z","git_url":"git://github.com/aturon/rust.git","ssh_url":"git@github.com:aturon/rust.git","clone_url":"https://github.com/aturon/rust.git","svn_url":"https://github.com/aturon/rust","homepage":"http://www.rust-lang.org","size":301685,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"85361528bc8f3880a2b2cffd15023c20bfe98282","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":724712,"name":"rust","full_name":"rust-lang/rust","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rust","description":"A safe, concurrent, practical language.","fork":false,"url":"https://api.github.com/repos/rust-lang/rust","forks_url":"https://api.github.com/repos/rust-lang/rust/forks","keys_url":"https://api.github.com/repos/rust-lang/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rust/teams","hooks_url":"https://api.github.com/repos/rust-lang/rust/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rust/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rust/events","assignees_url":"https://api.github.com/repos/rust-lang/rust/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rust/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rust/tags","blobs_url":"https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rust/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rust/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rust/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rust/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rust/subscription","commits_url":"https://api.github.com/repos/rust-lang/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rust/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang/rust/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rust/merges","archive_url":"https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rust/downloads","issues_url":"https://api.github.com/repos/rust-lang/rust/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rust/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rust/releases{/id}","created_at":"2010-06-16T20:39:03Z","updated_at":"2015-06-30T19:02:14Z","pushed_at":"2015-06-30T19:04:18Z","git_url":"git://github.com/rust-lang/rust.git","ssh_url":"git@github.com:rust-lang/rust.git","clone_url":"https://github.com/rust-lang/rust.git","svn_url":"https://github.com/rust-lang/rust","homepage":"http://www.rust-lang.org","size":637327,"stargazers_count":12447,"watchers_count":12447,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2391,"mirror_url":null,"open_issues_count":2121,"forks":2391,"open_issues":2121,"watchers":12447,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/26610"},"html":{"href":"https://github.com/rust-lang/rust/pull/26610"},"issue":{"href":"https://api.github.com/repos/rust-lang/rust/issues/26610"},"comments":{"href":"https://api.github.com/repos/rust-lang/rust/issues/26610/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/26610/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/26610/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rust/statuses/d264b0e0a2ddd5dcde998c10bb2f677fe2a35a2a"}}}}