{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/25894","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/25894/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/25894/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/25894/events","html_url":"https://github.com/rust-lang/rust/issues/25894","id":82717169,"number":25894,"title":"unsafe: ScopedKey allows for Sync-ification of non-Sync data","user":{"login":"Manishearth","id":1617736,"avatar_url":"https://avatars.githubusercontent.com/u/1617736?v=3","gravatar_id":"","url":"https://api.github.com/users/Manishearth","html_url":"https://github.com/Manishearth","followers_url":"https://api.github.com/users/Manishearth/followers","following_url":"https://api.github.com/users/Manishearth/following{/other_user}","gists_url":"https://api.github.com/users/Manishearth/gists{/gist_id}","starred_url":"https://api.github.com/users/Manishearth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Manishearth/subscriptions","organizations_url":"https://api.github.com/users/Manishearth/orgs","repos_url":"https://api.github.com/users/Manishearth/repos","events_url":"https://api.github.com/users/Manishearth/events{/privacy}","received_events_url":"https://api.github.com/users/Manishearth/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/rust/labels/A-threads","name":"A-threads","color":"d7e102"},{"url":"https://api.github.com/repos/rust-lang/rust/labels/I-nominated","name":"I-nominated","color":"e10c02"},{"url":"https://api.github.com/repos/rust-lang/rust/labels/P-high","name":"P-high","color":"eb6420"},{"url":"https://api.github.com/repos/rust-lang/rust/labels/T-libs","name":"T-libs","color":"bfd4f2"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2015-05-30T06:07:01Z","updated_at":"2015-05-30T19:11:24Z","closed_at":null,"body":"There is an [`unsafe impl<T> Sync for KeyInner<T> { }`](https://github.com/rust-lang/rust/blob/master/src/libstd/thread/scoped_tls.rs#L196) in the scoped TLS module, which allows for sharing of data that wasn't meant to be shared.\r\n\r\nAn unqualified `unsafe impl<T> Sync for Foo { }` should *only* be used when `Foo` provides some sort of threadsafe locking mechanism. `KeyInner` and `ScopedKey` do not.\r\n\r\nThis lets us, for example, clone an `Rc` or `RefCell` between threads, in safe code:\r\n\r\n\r\n```rust\r\nscoped_thread_local!(static RC: Rc<u8>);\r\nfn main() {\r\n RC.set(&Rc::new(1), ||{\r\n     let y = &RC;\r\n     let guard = scoped(|| {\r\n        println!(\"Started 1\");\r\n        y.with(|slot|{\r\n            for i in 1..10 {\r\n                println!(\"Cloned in 1\");\r\n                slot.clone();\r\n                sleep_ms(10);\r\n            }\r\n        });\r\n        println!(\"Ended 1\");\r\n     });\r\n     println!(\"Started 0\");\r\n     y.with(|slot| {\r\n            for i in 1..10 {\r\n                println!(\"Cloned in 0\");\r\n                slot.clone();\r\n                sleep_ms(10);\r\n            }\r\n     });\r\n     println!(\"Ended 0\");\r\n     guard.join();\r\n });\r\n}\r\n```\r\n\r\n[playpen](http://is.gd/fhErmT)\r\n\r\nHere, we have `Rc` clones from different threads being interleaved, which can cause unsafety if there's a race on the refcount. We could also cause unsafety with a `RefCell`, or any other non-Sync type. `ScopedKey` basically lets us share `&T` across threads even if `T: !Sync`. I put the sleeps in there because somehow without them the routines are run serially.\r\n\r\nNote that this is not a problem with the `scoped()` API. I'm using `scoped()` here because to exploit `&T: Send, T:!Sync` one needs to be able to share across threads, and `Arc` has an additional `Send` bound which `ScopedKey` doesn't satisfy. Any usable `scoped` API will probably have to make the assumption that `&T: Send iff T:Sync`. Nor is this a problem with `Rc`, since it can be done with `RefCell`, too.\r\n\r\n\r\nSolution: Make it `unsafe impl<T: Sync> Sync for KeyInner<T> { }`\r\n\r\n... I think. I'm not familiar with this API, and I'm not sure why it's even `Sync` in the first place."},"comment":{"url":"https://api.github.com/repos/rust-lang/rust/issues/comments/107076545","html_url":"https://github.com/rust-lang/rust/issues/25894#issuecomment-107076545","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/25894","id":107076545,"user":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"created_at":"2015-05-30T19:11:24Z","updated_at":"2015-05-30T19:11:24Z","body":"@pythonesque in a `static`, borrows are `&'static`, I didn't even think of that.\r\nFirst off, a global static shouldn't be allowed to borrow a `#[thread_local]` static.\r\nAnd in general, having borrows in a `#[thread_local]` is going to be difficult to support, except for non-`Sync` data, because they would be `'static` right now.\r\n\r\nWe could disallow `Sync` borrows or we could give some kind of scope to those borrows.\r\n\r\nWhich makes me think, as a compromise between a `thread_local` lifetime and `'static`, there could be a `thread_local` pseudo-(rvalue)-scope.\r\nCombined with the ability to leave out `'static` in globals' type (or not having a type at all), the scope should bubble up into users of those statics.\r\n\r\nThey would behave as if they were borrowed before everything else in the function where they're used, but still not `'static` (and they can't be returned from functions)."}}