Skip to content

Change TIO* constants to c_ulong, as ioctl() requires c_ulong #704

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

Closed
wants to merge 1 commit into from
Closed

Change TIO* constants to c_ulong, as ioctl() requires c_ulong #704

wants to merge 1 commit into from

Conversation

mneumann
Copy link
Contributor

This for example fixes code like:

https://github.com/a8m/pb/blob/master/src/tty/unix.rs#L22

where we would need an "as c_ulong" otherwise.

This for example fixes code like:

https://github.com/a8m/pb/blob/master/src/tty/unix.rs#L22

where we would need an "as c_ulong" otherwise.
@alexcrichton
Copy link
Member

Unfortunately this is a breaking change for now so I'll tag this as 1.0 cleanup

@mneumann
Copy link
Contributor Author

mneumann commented Aug 2, 2017

The problem is that for some operating systems these constants are already defined in (rusty) libc as u_long, whereas for some others these are (incorrectly) defined as c_int. Many libraries are only tested on Linux, where these constants are defined as u_long, so these libraries are broken on other OSes like FreeBSD or DragonFly. This leads to a lot of work to fix these small things. Even worse, this leads to code like TIOCGETD as c_ulong all over the place in these libraries, which is only correct as long as ioctl() really is c_ulong.

I assume a 1.0 release is light years away. Having things broken on BSDs is bad IMHO (it frustrates me to spend so much time fixing things like that :(). Can we at least introduce a type ioctl_fun = c_ulong, so that other libraries can safely cast any TIO* constant (any ioctl() request code) to the correct type?

@alexcrichton
Copy link
Member

Oh I agree it's frustrating! On the other hand though this is a breaking change. I hope that 1.0 is not lightyears away, though. Hopefully just on the order of months.

@mneumann
Copy link
Contributor Author

mneumann commented Aug 7, 2017

@alexcrichton: Thanks! I understand it's a breaking change, but I'd argue that it's currently broken on these platforms as dependent crates won't currently build on Free- and DragonFly BSD. A few months I can wait :)

@asomers
Copy link
Contributor

asomers commented Apr 26, 2018

It's not a breaking change if it only affects code that doesn't compile as-is. Can we please have this pre-1.0, unless somebody's aware of code that is using the incorrect types yet somehow actually works?

@alexcrichton
Copy link
Member

@asomers code which works around these being the wrong types will break if this lands, and it's definitely possible to write working code today that breaks if these types change

@mneumann
Copy link
Contributor Author

@asomers @alexcrichton I think code that works around this will do an "as u32" cast or an "into()", so whatever type libc exports, it will not break anything.

@alexcrichton
Copy link
Member

This breaks code like let x: c_uint = TIOCEXCL because the type changes

@mneumann
Copy link
Contributor Author

@alexcrichton : Correct, that would break this code. But, that code would be broken anyway, as x would be passed to ioctl, which expects an u_long ;-). Well, I can live with the workaround, as it doesn't involve much code, but on the other hand, this workaround will very likely never be removed from the code :). A more general question arises, how to proceed with bugs in the API (and this is one). Imagine that we would have exposed ioctl with an invalid signature... would we change it and break the API?

@alexcrichton
Copy link
Member

Sorry but we're just not accepting breaking changes right now, if and when 1.0 happens we can change this but until that time FreeBSD is a "high enough tier" that we don't accept breakage for it.

@asomers
Copy link
Contributor

asomers commented May 1, 2018

Speaking as a FreeBSD committer, the potential breakage that would be caused by merging this PR is less bad than the actual breakage that is caused by not merging it. This bug breaks a lot of crates that were originally developed on Linux when they try to go to FreeBSD.

@alexcrichton
Copy link
Member

If a crater-like run could be performed showing that this doesn't have any practical breakage in the ecosystem on FreeBSD then I think we would be able to make this change, but without that knowledge we simply cannot make breaking changes blindly

@Mark-Simulacrum
Copy link
Member

Would it be sufficient to patch libc with this merged and then run Crater in check-only mode targeting FreeBSD? Or is more than that needed?

@alexcrichton
Copy link
Member

I believe so yeah, but I don't think there's a lot of precedent for doing this on non-Linux platforms

dcuddeback added a commit to dcuddeback/serial-rs that referenced this pull request Jun 22, 2018
After migrating from ioctl-rs to libc for `ioctl()` calls, compilation
fails on FreeBSD and DragonFlyBSD with type errors because some TIO*
constants are defined as `c_uint` when `ioctl()` expects the `request`
parameter to be `c_ulong`.

Fixing the types in libc is considered a breaking change, so probably
won't happen until the next major version bump [1]. A reasonable
work-around is to cast the constants to the expected type with `into()`:

    ioctl(fd, TIOCEXCL.into())

This allows the constants to be used similarly to how one would use a
`#define` in C, by letting the compiler convert the constant to the
appropriate type [2]. Since Rust is more strict about numerical type
conversions, this requires an explicit call to `into()`, which invokes
type inference to work out the final type and avoids the need to name
types explicitly (such as `TIOCEXCL as c_ulong`). Thus, this is portable
across platforms with different types for the `request` parameter of
`ioctl()`. This also won't break when libc changes the declared type for
TIO* constants to the correct type.

[1] rust-lang/libc#704

[2] Only lossless conversions (from smaller to larger type) implement
    `From` and `Into`. If TIO* constants were defined with a larger type
    than what `ioctl()` expects, then this would not compile.
@gnzlbg
Copy link
Contributor

gnzlbg commented Feb 20, 2019

@mneumann could you rebase this on top of master ?

While this only affects FreeBSD, the APIs it touches are not super rare. I'd like to merge this tentatively and do a release that only contains this change, and then, update libc in rust-lang/rust with this change.

If nobody complains for a reasonable amount of time, we can assume that this did not broke anybody. Otherwise, we'll have to yank that libc release, and revert this change from master, but we can hopefully do that during the nightly cycle as usual.

@asomers
Copy link
Contributor

asomers commented Feb 20, 2019

@gnzlbg isn't this what crater is for?

@gnzlbg
Copy link
Contributor

gnzlbg commented Feb 20, 2019

@asomers crater can check whether a rust-lang/rust PR breaks something, so when we upgrade libc in rust-lang/rust, we could do a crater run to check that. However, AFAIK, crater cannot be used yet to check whether a PR to a crate on crates.io would break its dependencies.

IIRC, using the bundled libc actually requires a nightly feature (feature(libc)), so I don't know how many crates are doing that instead of using libc from crates.io, so I don't know how useful the crater run would be. We should do this anyways though, but it might well be that doing a crates.io release breaks users that the crater run won't detect.

@bors
Copy link
Contributor

bors commented May 7, 2020

☔ The latest upstream changes (presumably #1587) made this pull request unmergeable. Please resolve the merge conflicts.

@pietroalbini pietroalbini deleted the branch rust-lang:master May 15, 2023 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants