Skip to content
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

The signature of "execv" | "execve" | "execvp" | "fexecve" is incorrect #1272

Closed
gnzlbg opened this issue Feb 22, 2019 · 15 comments · Fixed by #3597
Closed

The signature of "execv" | "execve" | "execvp" | "fexecve" is incorrect #1272

gnzlbg opened this issue Feb 22, 2019 · 15 comments · Fixed by #3597

Comments

@gnzlbg
Copy link
Contributor

gnzlbg commented Feb 22, 2019

The type of argv is *const *const c_char but should be *const *mut c_char. With the current incorrect signatures, libc-test fails for these APIs, but this does not surface because these tests are skipped. With the fixed signatures, all tests pass.

AFAICT, this affects all unix targets.

@gnzlbg gnzlbg added the C-bug Category: bug label Feb 22, 2019
gnzlbg added a commit to gnzlbg/libc that referenced this issue Feb 22, 2019
This cleans up the build.rs of `libc-test` for apple targets.

I wanted to update the docker containers of some targets so that we can start
testing newer currently-skipped APIs properly, but it is impossible to figure
out which headers and APIs are skipped for each target.

This PR separates the testing of apple targets into its own self-contained
function. This allows seeing exactly which headers are included, and which items
are skipped. A lot of work will be required to separate the testing of all major
platforms and make the script reasonable.

During the clean up, I discovered that, at least for apple targets, deprecated
but not removed APIs are not tested. I re-enabled testing for those, and fixed
`daemon`, which was not properly linking its symbol. I also added the
`#[deprecated]` attribute to the `#[deprecated]` APIs of the apple targets. The
attribute is available since Rust 1.9.0 and the min. Rust version we support is
Rust 1.13.0.

Many other APIs are also currently not tested "because they are weird" which I
interpret as "the test failed for an unknown reason", as a consequence:

* the signatures of execv, execve, and execvp are incorrect (see
  rust-lang#1272)

* the `sig_t` type is called `sighandler_t` in libc for some reason:
  rust-lang#1273

This probably explains why some other things, like the
`sa_handler`/`sa_sigaction` fields of `sigaction` were skipped. The field is
actually a union, which can be either a `sig_t` for the `sa_handler` field, or
some other type for the `sa_sigaction` field, but because the distinction was
not made, the field was not checked.

The latest ctest version can check volatile pointers, so a couple of skipped
tests are now tested using this feature.
gnzlbg added a commit to gnzlbg/libc that referenced this issue Feb 22, 2019
This cleans up the build.rs of `libc-test` for apple targets.

I wanted to update the docker containers of some targets so that we can start
testing newer currently-skipped APIs properly, but it is impossible to figure
out which headers and APIs are skipped for each target.

This PR separates the testing of apple targets into its own self-contained
function. This allows seeing exactly which headers are included, and which items
are skipped. A lot of work will be required to separate the testing of all major
platforms and make the script reasonable.

During the clean up, I discovered that, at least for apple targets, deprecated
but not removed APIs are not tested. I re-enabled testing for those, and fixed
`daemon`, which was not properly linking its symbol. I also added the
`#[deprecated]` attribute to the `#[deprecated]` APIs of the apple targets. The
attribute is available since Rust 1.9.0 and the min. Rust version we support is
Rust 1.13.0.

Many other APIs are also currently not tested "because they are weird" which I
interpret as "the test failed for an unknown reason", as a consequence:

* the signatures of execv, execve, and execvp are incorrect (see
  rust-lang#1272)

* the `sig_t` type is called `sighandler_t` in libc for some reason:
  rust-lang#1273

This probably explains why some other things, like the
`sa_handler`/`sa_sigaction` fields of `sigaction` were skipped. The field is
actually a union, which can be either a `sig_t` for the `sa_handler` field, or
some other type for the `sa_sigaction` field, but because the distinction was
not made, the field was not checked.

The latest ctest version can check volatile pointers, so a couple of skipped
tests are now tested using this feature.
bors added a commit that referenced this issue Feb 22, 2019
Clean libc-test for apple targets

This cleans up the build.rs of `libc-test` for apple targets.

I wanted to update the docker containers of some targets so that we can start testing newer currently-skipped APIs properly, but it is impossible to figure out which headers and APIs are skipped for each target, which has to change if we update the glibc version in one Linux container but not the other (updating them all at once is just madness).

This PR separates the testing of apple targets into its own self-contained function. This allows seeing exactly which headers are included, and which items are skipped. A lot of work will be required to separate the testing of all major platforms and make the script reasonable.

During the clean up, I discovered that, at least for apple targets, deprecated but not removed APIs are not tested. I re-enabled testing for those, and fixed `daemon`, which was not properly linking its symbol. I also added the `#[deprecated]` attribute to the `#[deprecated]` APIs of the apple targets. The attribute is available since Rust 1.9.0 and the min. Rust version we support is Rust 1.13.0.

Many other APIs are also currently not tested "because they are weird" which I interpret as "the test failed for an unknown reason", as a consequence:

* the signatures of execv, execve, and execvp are incorrect (see #1272)

* the `sig_t` type is called `sighandler_t` in libc for some reason: #1273

This probably explains why some other things, like the `sa_handler`/`sa_sigaction` fields of `sigaction` were skipped. The field is actually a union, which can be either a `sig_t` for the `sa_handler` field, or some other type for the `sa_sigaction` field, but because the distinction was not made, the field was not checked.

The latest ctest version can check volatile pointers, so a couple of skipped tests are now tested using this feature.
@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

@asomers it would be better to start fixing these in freebsd

@semarie it would be good to know if their signature is also incorrect in openbsd and netbsd (e.g. by trying to remove their "skip" in libc-test/build.rs since we can't check that in CI.

I'll try to roll in a fix for Android.

After that is done, we can fix these on Linux, and do an update upstream, crater run, etc.

@asomers
Copy link
Contributor

asomers commented May 23, 2019

Why do you think it would be best to start with FreeBSD? It seems that the same problem exists on Linux.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

We could try rolling this change for all targets at once as well. These APIs are available on all tier-1 targets, so I just thought that it might be "safer" to try to roll the change for less used targets first, and if there aren't any problems, only then attempt that for the tier-1 targets.

AFAICT libstd does not use these APIs, so it is unclear to me how many people are using them (is anybody using them at all?) and how (e.g. whether changing the mutability of that pointer would be a breaking change for them or not).

@asomers
Copy link
Contributor

asomers commented May 23, 2019

Well, Nix uses libc::execve. And the proposed change will break Nix. In fact, I think the error here is not in libc. The error is in execve's signature as mandated by POSIX. POSIX says "The argv[] and envp[] arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.", yet it still specifies a non-const array for argv. That's a bug. It's probably a very old bug, dating to the days before C had a const keyword. But given that "shall not be modified" requirement, I think that it's safe (and preferable) for libc to use a *const *const c_char argument.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html

@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

Doesn't the "except as a consequence of replacing the process image." imply that those can actually be modified ? (EDIT: I thought replacing the process image was the main point of calling these functions).

@asomers
Copy link
Contributor

asomers commented May 23, 2019

I interpret that as meaning that they may be modified in the child's image, but not in the parent's image. The constness of the pointer only matters from the perspective of the parent.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

Makes sense. The question still is, why should we do something different than C here ? If the C headers have a bug, then that would be a good enough reason, but I am not sure if that's the case here.

@semarie
Copy link
Contributor

semarie commented May 23, 2019

Regarding openbsd, the signature is incorrect.

correct definitions for openbsd are:

  • pub fn execvpe(file: *const ::c_char, argv: *const *mut ::c_char, envp: *const *mut ::c_char) -> ::c_int;
  • pub fn execv(prog: *const c_char, argv: *const *mut c_char) -> ::c_int;
  • pub fn execve(prog: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char)
  • pub fn execvp(c: *const c_char, argv: *const *mut c_char) -> ::c_int;

@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

@semarie thanks, yes that is the signature that POSIX prescribes so basically all targets right now have this "issue". ABI-wise, a pointer is a pointer, and whether it is const or mut doesn't matter much.

@asomers
Copy link
Contributor

asomers commented May 23, 2019

If we were writing libc from scratch, then we should probably just copy the C headers and require users to deal with the wrong constness. However, "fixing" libc at this point would break released versions of crates like Nix. I don't think the payoff is worth the pain.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented May 23, 2019

I tend to agree. Do you think that if we ever do a new breaking release of libc, we should probably fix this ? We probably have to that at some point anyways, to be able to properly use unions, flexible array members, etc. but that would be way down the road probably.

@asomers
Copy link
Contributor

asomers commented May 23, 2019

I suppose it wouldn't hurt if libc were breaking many more things at the same time. But it would have to be a major version bump.

@gnzlbg gnzlbg added breakage-candidate and removed C-bug Category: bug labels May 23, 2019
@rtzoeller
Copy link
Contributor

DragonFly BSD implemented fexecve(2) in the 6.0 release, based on the FreeBSD implementation.

While attempting to duplicate the FreeBSD definition, I stumbled across this issue. What's the desired signature for new Unix implementations of fexecve()? in libc?

Is it preferable to match the C definition, or the existing rust definitions?

@asomers
Copy link
Contributor

asomers commented Oct 19, 2021

I tend to think that you should stick with the current wrong, but really right, rust definition. That will certainly cause less pain for Rust users, at least.

@JohnTitor JohnTitor changed the title The signature of "execv" | "execve" | "execvp" is incorrect The signature of "execv" | "execve" | "execvp" | "fexecve" is incorrect Oct 20, 2021
bors added a commit that referenced this issue Oct 21, 2021
Add fexecve() to DragonFly

DragonFly 6.0 added support for `fexecve(2)`.

Implementing it with a mismatched signature from what C exposes, as outlined in #1272, for consistency with other platforms.

Tested with nix-rust/nix#1577
@safinaskar
Copy link

Same issue applies to posix_spawn*. As far as I see exec* are fixed on x86_64-unknown-linux-gnu, but posix_spawn* are not

safinaskar pushed a commit to safinaskar/libc that referenced this issue Feb 25, 2024
Yes, this makes the prototypes harder to use. And less intuitive.
But this makes them match headers, and thus now we can properly test
them. This fixes rust-lang#1272
safinaskar pushed a commit to safinaskar/libc that referenced this issue Feb 25, 2024
Yes, this makes the prototypes harder to use. And less intuitive.
But this makes them match headers, and thus now we can properly test
them. This fixes rust-lang#1272
safinaskar pushed a commit to safinaskar/libc that referenced this issue Feb 25, 2024
Yes, this makes the prototypes harder to use. And less intuitive.
But this makes them match headers, and thus now we can properly test
them. This fixes rust-lang#1272
safinaskar pushed a commit to safinaskar/libc that referenced this issue Feb 25, 2024
Yes, this makes the prototypes harder to use. And less intuitive.
But this makes them match headers, and thus now we can properly test
them. This fixes rust-lang#1272

Also we fix return types for some Windows exec* functions
Andy-Python-Programmer pushed a commit to Andy-Python-Programmer/libc that referenced this issue Mar 24, 2024
Yes, this makes the prototypes harder to use. And less intuitive.
But this makes them match headers, and thus now we can properly test
them. This fixes rust-lang#1272

Also we fix return types for some Windows exec* functions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants