From 2d032e488f62d3f59afacfe61e7c3b9e7a34828c Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Wed, 20 May 2015 02:28:30 -0400 Subject: [PATCH 1/2] liblibc: Fix prototype of functions taking `char *const argv[]` These functions do not modify their arguments, so they does not need mutable pointers. The C prototypes take a constant array of mutable C-strings, but that's a legacy quirk from before C had const (since string literals have type `char *`). The Rust prototypes had `*mut` in the wrong place, anyway: to match the C prototypes, it should have been `*const *mut c_char`. Also fix the one caller of execvp in libstd, which now no longer needs an unsafe cast. --- src/liblibc/lib.rs | 32 ++++++++++++++++---------------- src/libstd/sys/unix/process.rs | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 3d19e95211e8d..0a70e53b17e08 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5490,17 +5490,17 @@ pub mod funcs { pub fn dup2(src: c_int, dst: c_int) -> c_int; #[link_name = "_execv"] pub fn execv(prog: *const c_char, - argv: *mut *const c_char) -> intptr_t; + argv: *const *const c_char) -> intptr_t; #[link_name = "_execve"] - pub fn execve(prog: *const c_char, argv: *mut *const c_char, - envp: *mut *const c_char) + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> c_int; #[link_name = "_execvp"] pub fn execvp(c: *const c_char, - argv: *mut *const c_char) -> c_int; + argv: *const *const c_char) -> c_int; #[link_name = "_execvpe"] - pub fn execvpe(c: *const c_char, argv: *mut *const c_char, - envp: *mut *const c_char) -> c_int; + pub fn execvpe(c: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> c_int; #[link_name = "_getcwd"] pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; #[link_name = "_getpid"] @@ -5684,12 +5684,12 @@ pub mod funcs { pub fn dup(fd: c_int) -> c_int; pub fn dup2(src: c_int, dst: c_int) -> c_int; pub fn execv(prog: *const c_char, - argv: *mut *const c_char) -> c_int; - pub fn execve(prog: *const c_char, argv: *mut *const c_char, - envp: *mut *const c_char) + argv: *const *const c_char) -> c_int; + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> c_int; pub fn execvp(c: *const c_char, - argv: *mut *const c_char) -> c_int; + argv: *const *const c_char) -> c_int; pub fn fork() -> pid_t; pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; @@ -5699,7 +5699,7 @@ pub mod funcs { pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; pub fn getlogin() -> *mut c_char; - pub fn getopt(argc: c_int, argv: *mut *const c_char, + pub fn getopt(argc: c_int, argv: *const *const c_char, optstr: *const c_char) -> c_int; pub fn getpgrp() -> pid_t; pub fn getpid() -> pid_t; @@ -5749,19 +5749,19 @@ pub mod funcs { pub fn dup(fd: c_int) -> c_int; pub fn dup2(src: c_int, dst: c_int) -> c_int; pub fn execv(prog: *const c_char, - argv: *mut *const c_char) -> c_int; - pub fn execve(prog: *const c_char, argv: *mut *const c_char, - envp: *mut *const c_char) + argv: *const *const c_char) -> c_int; + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> c_int; pub fn execvp(c: *const c_char, - argv: *mut *const c_char) -> c_int; + argv: *const *const c_char) -> c_int; pub fn fork() -> pid_t; pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; pub fn getegid() -> gid_t; pub fn geteuid() -> uid_t; pub fn getgid() -> gid_t; pub fn getlogin() -> *mut c_char; - pub fn getopt(argc: c_int, argv: *mut *const c_char, + pub fn getopt(argc: c_int, argv: *const *const c_char, optstr: *const c_char) -> c_int; pub fn getuid() -> uid_t; pub fn getsid(pid: pid_t) -> pid_t; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index f4bc597304097..3ed886fe47780 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -311,7 +311,7 @@ impl Process { if !envp.is_null() { *sys::os::environ() = envp as *const _; } - let _ = libc::execvp(*argv, argv as *mut _); + let _ = libc::execvp(*argv, argv); fail(&mut output) } From 6771723c40054c969072a7c95d3e19e3a269d01f Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Wed, 20 May 2015 03:29:54 -0400 Subject: [PATCH 2/2] liblibc: Prototype getopt on Linux as taking a mutable argument This is a GNU-specific weirdness in its getopt implementation (presumably assuming that the function will be called with a mutable argv from main). Quoting the "conforming to" section of its manpage: "POSIX.2 and POSIX.1-2001, provided the environment variable POSIXLY_CORRECT is set. Otherwise, the elements of argv aren't really const, because we permute them." Since we have no way to enforce that that variable is set in an FFI binding, the safe thing to do is to mark the function as taking a mutable array. --- src/liblibc/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 0a70e53b17e08..a25d10e8498af 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5699,8 +5699,13 @@ pub mod funcs { pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; pub fn getlogin() -> *mut c_char; + #[cfg(not(target_os = "linux"))] pub fn getopt(argc: c_int, argv: *const *const c_char, optstr: *const c_char) -> c_int; + // GNU getopt(3) modifies its arguments despite the prototype. + #[cfg(target_os = "linux")] + pub fn getopt(argc: c_int, argv: *mut *mut c_char, + optstr: *const c_char) -> c_int; pub fn getpgrp() -> pid_t; pub fn getpid() -> pid_t; pub fn getppid() -> pid_t;