-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type alias can be used to bypass privacy check #28450
Comments
triage: I-nominated cc @nrc, @rust-lang/lang |
The workings around this were always a little subtle to me, so I'm not 100% sure if this is working as intended or just a bug where we didn't follow a Note that a fix for this (if we want one) is likely to have a lot of fallout so we'd definitely want to run it through crater to select a mitigation strategy. |
|
I think this (that a type alias can increase visibility) is a feature, not a bug. The fact that we can re-export functions without re-exporting all the types they refer to is unfortunate, but kind of intentional. The last time this kind of thing was discussed, we decided that we would not try to be complete in the checking of private types in public signatures, since it is way too complex and we'd only try to enforce a syntactic distinction, rather than taking reachability, etc. into account. |
This does not, in fact, offer any real protection: trait Pointer { type Pointee; }
impl<T:?Sized> Pointer for *const T { type Pointee = T; }
type __CFArray = <CFArrayRef as Pointer>::Pointee; |
@nrc yeah that was my vague recollection as well, but I thought the rule we were going for was "if this isn't |
I would expect a |
thematically related to #28325, at least |
triage: P-high -- backwards compat |
This is trivial to fix in some sense... but the usage of a type alias isn't really integral to the original testcase. Consider: #![crate_type="lib"]
mod b {
mod a {
pub struct S1;
pub struct S2(pub S1);
}
pub use self::a::S2;
}
pub fn g(s : b::S2) {
let s = s.0; // Oops, I can't name the type of the field.
} |
@eefriedman that is ok, because the struct was declared On Thu, Sep 17, 2015 at 7:51 PM, eefriedman [email protected]
|
I'm curious whether we expect the following to be allowed: type Foo = u8;
pub fn foo(f: Foo) {} That is, if you use a private type alias to reference a public type in a signature -- is that OK? Currently the snippet fails to compile. Fixing the original issue turns up some cases within |
@aturon
However, (I'm currently rewriting all this, I've finished |
Another very simpe hole in
|
@petrochenkov OK, thanks for the heads up that you're doing a rewrite. I was going to look at a couple issues in this vicinity as well, but maybe you can factor them in:
The current goal is to get all of this checking in line with the relevant RFC. We may want to loosen some of the rules, eventually, but for now we should hew toward the conservative spec. The fundamental guarantee in the spec is that a type definition may only escape a module if it is marked I definitely agree that |
I'm not so sure. Here's a few examples: type Foo = Arc<Mutex<io::Read + Send + 'static>>;
pub fn foo(x: Foo) {} In this example, I've found myself wanting to use a pub use self::inner::Foo;
pub type Bar = self::inner::Bar;
mod inner {
struct Foo;
struct Bar;
} In this example, I feel that the re-export should be valid, but the I would expect Any desire to use |
@seanmonstar |
@seanmonstar
without allowing users to change the parameters by themselves. |
I don't think this is a hole. Rather, I think it is legal to (I happen to think we should extend this system somewhat, probably by allowing you to limit pub declarations to some enclosing modules, but this is the system we have today.)
I don't understand this restriction, can you clarify what it is? I think probably both |
(Unless by hole you just meant that we get link time errors, in which case I agree there is some sort of bug with the linker's code that identifies reachable symbols.) |
In this example that you gave: pub use self::inner::Foo;
pub type Bar = self::inner::Bar;
mod inner {
struct Foo;
struct Bar;
} The current rules are that both are in error. This is because |
I expect this to be in an error, as it is today. I find this mildly annoying sometimes, but it makes sense, since type aliases appear in rustdoc and so forth. |
In this case
If |
Now I'm reading the older edition of https://github.com/rust-lang/rfcs/blob/master/text/0136-no-privates-in-public.md written by @glaebhoerl and I like it better than the current version. Basically, Edit: with "new edition" it will be pretty hard to reduce the surface area of produced object files. |
(FWIW I like my original idea better too ;) the problem was basically that I didn't manage to figure out the right way to think about and specify the semantics in time (the one I wrote in the RFC was pretty confused, as far as I remember) and no one else seemed interested in trying, so we ended up with this less-ambitious formulation.) |
To some extent, this is water under the bridge, at least until another RFC is written. However, the problem with the initial formulation, from my POV, is that, under that formulation, just looking at a declaration (say, of a struct) did not give you the full story of its scoping. The story is simpler today: if you see One flaw, though, is that the story of All that said, I think that evaluating the overall reachability of items (versus checking whether they obey the "no private things in public APIs" rule) seems to just be two distinct concepts, and we have to deal with that. (That is, I'm not sure that collapsing both into one visitor is a good direction, though clearly they share some common code -- probably the bit that computes the successors to a given node in the reachability graph.) Evaluating the reachable set seems, however, to be a fairly straightforward process: it's just a DFS over the reachability graph, stopping at private edges, right? |
@nikomatsakis woops, I forgot to make the 2 internal structs public. // these do the same thing, and compile today
pub use self::internal::Foo;
pub type Bar = self::internal::Bar;
mod internal {
pub struct Foo;
pub struct Bar;
} I was suggesting that the privacy visitor should assume the type alias is a wrapper struct with a public type: @petrochenkov Yes, being able to do that is excellent, and I didn't mean to take that away. However, I'd want it to be illegal if any of those slots used a private item. pub struct Foo;
struct Bar;
pub type MaybeFoo = Option<Foo>; // <-- cool
pub type MaybeBar = Option<Bar>; // <-- compiles today, but i think it shouldnt |
I see, this is a good motivation, @seanmonstar |
Thanks @petrochenkov. Do you mind if I re-assign this and the other privacy bugs to you, since I've halted work on them while you work on your rewrite? |
@aturon |
Prohibiting non- Also, strictly speaking, almost everything involving public traits should be |
Some notes: This patch enforces the rules from [RFC 136](https://github.com/rust-lang/rfcs/blob/master/text/0136-no-privates-in-public.md) and makes "private in public" a module-level concept and not crate-level. Only `pub` annotations are used by the new algorithm, crate-level exported node set produced by `EmbargoVisitor` is not used. The error messages are tweaked accordingly and don't use the word "exported" to avoid confusing people (#29668). The old algorithm tried to be extra smart with impls, but it mostly led to unpredictable behavior and bugs like #28325. The new algorithm tries to be as simple as possible - an impl is considered public iff its type is public and its trait is public (if presents). A type or trait is considered public if all its components are public, [complications](https://internals.rust-lang.org/t/limits-of-type-inference-smartness/2919) with private types leaking to other crates/modules through trait impls and type inference are deliberately ignored so far. The new algorithm is not recursive and uses the nice new facility `Crate::visit_all_items`! Obsolete pre-1.0 feature `visible_private_types` is removed. This is a [breaking-change]. The two main vectors of breakage are type aliases (#28450) and impls (#28325). I need some statistics from a crater run (cc @alexcrichton) to decide on the breakage mitigation strategy. UPDATE: All the new errors are reported as warnings controlled by a lint `private_in_public` and lint group `future_incompatible`, but the intent is to make them hard errors eventually. Closes #28325 Closes #28450 Closes #29524 Closes #29627 Closes #29668 Closes #30055 r? @nikomatsakis
The function
public
is exported, accepting the typePriv
, even thoughPriv
is not exported.The text was updated successfully, but these errors were encountered: