Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd lint to deny transmuting &T to &mut T #24392
Conversation
rust-highfive
assigned
eddyb
Apr 13, 2015
This comment has been minimized.
This comment has been minimized.
|
r? @eddyb (rust_highfive has picked a reviewer for you, use r? to override) |
seanmonstar
referenced this pull request
Apr 13, 2015
Closed
Pool.inner_mut() and other mut methods are UB #2
seanmonstar
force-pushed the
seanmonstar:lint-transmute-mut
branch
from
6a9a49e
to
5fc357e
Apr 13, 2015
Manishearth
reviewed
Apr 14, 2015
| if let ast::ExprPath(..) = expr.node { | ||
| if let DefFn(did, _) = ty::resolve_expr(cx.tcx, expr) { | ||
| if def_id_is_transmute(cx, did) { | ||
| let typ = ty::node_id_to_type(cx.tcx, expr.id); |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
seanmonstar
Apr 14, 2015
Author
Contributor
I actually stole most of this code from rustc::middle::instrinsicck...
This comment has been minimized.
This comment has been minimized.
Manishearth
Apr 14, 2015
Member
I'm not sure why we need to go through resolve_expr here, actually.
We have transmute(a), where transmute(a) is an ExprCall (where the first Expr is an ExprPath) and a is some form of Expr. Just running expr_ty on both should be enough to get the types, without going through BareFnTy and whatnot.
This comment has been minimized.
This comment has been minimized.
seanmonstar
Apr 21, 2015
Author
Contributor
It seems it's needed to get to the DefId, so that we can determine if this method is actually std::mem::transmute, even if it's been imported as a different name. The BareFnTy is also needed to check the ABI.
Manishearth
reviewed
Apr 14, 2015
| if def_id.krate == ast::LOCAL_CRATE { | ||
| match cx.tcx.map.get(def_id.node) { | ||
| NodeForeignItem(ref item) if intrinsic => { | ||
| token::get_ident(item.ident) == |
This comment has been minimized.
This comment has been minimized.
Manishearth
Apr 14, 2015
Member
nit: we should probably compare the strings (there is a get() or a deref impl on Ident), not idents
Edit: as_str()
This comment has been minimized.
This comment has been minimized.
seanmonstar
Apr 21, 2015
Author
Contributor
Why compare the strings? It seems token::get_ident() doesn't return an ast::Ident (the fn name is misleading), but an InternedString. Comparing an interned string should be strictly faster than pulling out the original Strings and then doing a memcmp, right?
This comment has been minimized.
This comment has been minimized.
Manishearth
Apr 22, 2015
Member
Yeah, but you have to intern a string to get there, so you do the comparison anyway in the interning.
item.ident is an Ident and can be directly compared with "transmute" after an as_str()
This comment has been minimized.
This comment has been minimized.
|
I'll have another look later when I can access docs, but this looks good to me code-wise. There may be a way to avoid the csearch. I'm not certain if we want to add more lints though. @alexcrichton thoughts? |
This comment has been minimized.
This comment has been minimized.
|
I personally feel that we have far too many lints as-is, but I'm also quite biased! I don't believe we have a strict policy on what lints are included and which are not. |
This comment has been minimized.
This comment has been minimized.
|
So, this doesn't need to be a lint. It could be built in to the |
Manishearth
reviewed
Apr 14, 2015
| None | ||
| } | ||
|
|
||
| fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool { |
This comment has been minimized.
This comment has been minimized.
Manishearth
Apr 14, 2015
Member
I don't think we need the csearch here. Just check that the ABI is rust-intrinsic and that the path matches transmute
This comment has been minimized.
This comment has been minimized.
seanmonstar
Apr 14, 2015
Author
Contributor
I don't know enough yet, so likely ignore me. However, it looks like csearch is needed if the fn def_id is not defined in the same crate (so most cases), right?
This comment has been minimized.
This comment has been minimized.
Manishearth
Apr 14, 2015
Member
Well, you don't need to lookup the def, the name of the function is already with you in the ExprPath -- transmute(a) is an ExprCall(ExprPath("transmute"), vec![whatever a is])
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
seanmonstar
Apr 15, 2015
Author
Contributor
@Manishearth oh, what about use std::mem::transmute as trans? I imagine that's why the original fn is being looked up?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
This would fix #13146 |
seanmonstar
force-pushed the
seanmonstar:lint-transmute-mut
branch
from
5fc357e
to
09047f7
Apr 22, 2015
This comment has been minimized.
This comment has been minimized.
|
@Manishearth okay, using Also added Also, nominate for beta, since breaking at 1.1 seems impossible? |
This comment has been minimized.
This comment has been minimized.
|
triage: beta-nominated wonder if that works |
dotdash
added
the
beta-nominated
label
Apr 22, 2015
This comment has been minimized.
This comment has been minimized.
|
Anything else required for this? |
This comment has been minimized.
This comment has been minimized.
|
Looks good to me. I'll let @alexcrichton r+ this though |
nrc
assigned
alexcrichton
and unassigned
eddyb
Apr 23, 2015
pnkfelix
added
the
beta-accepted
label
Apr 23, 2015
This comment has been minimized.
This comment has been minimized.
|
from nominated to (nominated, accepted) |
This comment has been minimized.
This comment has been minimized.
|
Maybe the documentation of |
This comment has been minimized.
This comment has been minimized.
|
I still personally feel that lints like this are too specific to be that beneficial. For example this does not provide an iron-clad guarantee that this kind of "undefined behavior" isn't actually happening. The biggest abuser of |
This comment has been minimized.
This comment has been minimized.
|
IMO if we crack down on UB now, even with semi effective solutions like this one; it will still be a net gain in the future when there isn't any UB abuse scattered all over the place. -----Original Message----- I still personally feel that lints like this are too specific to be that beneficial. For example this does not provide an iron-clad guarantee that this kind of "undefined behavior" isn't actually happening. The biggest abuser of &mut self in the standard library, channels, is not caught by this change and probably wouldn't with any form of lint. I know that lints are not meant to provide an iron-clad guarantee, but I'm just not sure how useful this will end up being (especially being deny-by-default). |
This comment has been minimized.
This comment has been minimized.
|
I happen to believe that any lint that's supposed to be so important to be deny-by-default should be a feature of the language proper rather than being left up to a lint. I dunno, maybe the perfect is the enemy of the good... |
This comment has been minimized.
This comment has been minimized.
|
I'm open to warn by default |
This comment has been minimized.
This comment has been minimized.
|
Since this is undefined behavior, I think it should be deny by default. If you somehow know better, you can add an I originally thought of adding this code to |
This comment has been minimized.
This comment has been minimized.
|
I do agree with @bstrie that it seems weird to implement a check for undefined behavior as a lint instead of some sort of other error. A lint is an admission that "sure, you may want to actually do this sometimes, just not all the time", but I'm not sure that we have a set of behavior where you would indeed want this kind of a transmute. |
This comment has been minimized.
This comment has been minimized.
|
I don't know, I'm wary of building in "no, you should never need this" into a language; there should always be a way to do stuff like this, just that there are more hoops to jump through. |
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton I guess it's technically not undefined behavior to transmute if you already are using an unsafe {
let val = &*self.foo.get();
let val_mut: &mut Foo = transmute(val);
}Though, at that point, you should likely just do |
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton I think that quote from nwin is regarding the repr + drop lint, not this one? As for motivation, it actually came from seeing it appear in crates on crates.io, such as the issue I linked regarding pool, which did this transmute in several places. I likewise started with a transmute in hyper's I genuinely think that more often than not, it's a mistake because people don't realize it is undefined behavior, and pointing it out and suggesting |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@seanmonstar yes it was not about this one, admittedly ambiguously formulated. |
This comment has been minimized.
This comment has been minimized.
|
tomaka:
Lints – and static code analysis in general – are regarded very positively in many language communities. E.g. many front-end devs won't allow code that doesn't pass jslint, and I (a seasoned Java dev with more than a decade of experience) have FindBugs check my code at all times. It's cheap and will sometimes catch oversights. Errors happen. Having an additional safety net cannot hurt. Rust is already very good in this regard. So while I certainly agree that not all lints belong in rustc, I don't feel that we have too many. But I'm just a rust newbie, so feel free to ignore my opinion. |
This comment has been minimized.
This comment has been minimized.
|
I'm with @seanmonstar on this one. The issue that I had (linked above) was something that a) seems to work fine, b) I had every reason to believe would work (exclusive ownership was guaranteed elsewhere), and c) should never be allowed by anyone serious about things. The suggestion to do the transmute was made by a seasoned (unnamed) Rust-y in IRC. Now that I've internalized some of the things on the UB link I know a bit better, but I could really use the help from lints written by smarter folks. |
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
May 5, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
|
seanmonstar
force-pushed the
seanmonstar:lint-transmute-mut
branch
from
f224446
to
50d406b
May 5, 2015
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton updated the failing run-pass tests |
alexcrichton
reviewed
May 5, 2015
| @@ -22,5 +22,5 @@ fn bar<T>(_: &mut A, _: &T) {} | |||
|
|
|||
| fn foo<T>(t: &T) { | |||
| let b = B; | |||
| bar(unsafe { mem::transmute(&b as &A) }, t) | |||
| bar(&mut b as &mut A, t) | |||
This comment has been minimized.
This comment has been minimized.
alexcrichton
May 5, 2015
Member
Did you run this test? I think that the binding to b needs to be mut for this to work? (I'd recommend being sure to run the tests for these cases).
This comment has been minimized.
This comment has been minimized.
seanmonstar
May 5, 2015
Author
Contributor
I pushed before running (the run caught what you noticed), since I needed to rebuild and it'd take a while. It's all done, and I'm pushing the corrections that make these 2 tests pass.
seanmonstar
force-pushed the
seanmonstar:lint-transmute-mut
branch
from
50d406b
to
5b0d828
May 5, 2015
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
May 6, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
|
seanmonstar
added some commits
Apr 13, 2015
seanmonstar
force-pushed the
seanmonstar:lint-transmute-mut
branch
from
5b0d828
to
5624cfb
May 6, 2015
This comment has been minimized.
This comment has been minimized.
|
Sigh, had improved the lint message from review comments, but forgot to adjust the expected error in the compile-fail. Then the subsequent check-stage1-rpass for the previous failure hadn't caught it either. Now cfail passes as well. |
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
May 6, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
bors
merged commit 5624cfb
into
rust-lang:master
May 7, 2015
brson
removed
the
beta-nominated
label
May 8, 2015
This comment has been minimized.
This comment has been minimized.
|
Thanks a ton for merging this; to add to the support, after this lint appeared I found the bug in |
seanmonstar commentedApr 13, 2015
The UnsafeCell documentation says it is undefined behavior, so people shouldn't do it.
This happened to catch one case in libstd that was doing this, and I switched that to use an UnsafeCell internally.
Closes #13146