std::env::args() segfaults when calling gst-launch-1.0 with -v option
Hi,
it seems that when using std::env::args()
inside a gstreamer plugin and launching said plugin with gst-launch-1.0, this causes a segfault.
Steps to reproduce:
- clone this repo
cd tutorials
- add a call to
std::env::args()
to an example plugin
diff --git a/tutorial/src/sinesrc/imp.rs b/tutorial/src/sinesrc/imp.rs
index 24364680..a93cd5c2 100644
--- a/tutorial/src/sinesrc/imp.rs
+++ b/tutorial/src/sinesrc/imp.rs
@@ -55,6 +55,7 @@ struct Settings {
impl Default for Settings {
fn default() -> Self {
+ dbg!(std::env::args());
Settings {
samples_per_buffer: DEFAULT_SAMPLES_PER_BUFFER,
freq: DEFAULT_FREQ,
cargo build --release --target=x86_64-unknown-linux-gnu
GST_PLUGIN_PATH=$PWD/../target/x86_64-unknown-linux-gnu/release gst-launch-1.0 -v rssinesrc ! autoaudiosink
- It segfaults. Ommitting the
-v
flag fixes this.
I did some print-debugging and edited ~/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs
so the clone
function looks like this:
fn clone() -> Vec<OsString> {
unsafe {
// Load ARGC and ARGV, which hold the unmodified system-provided
// argc/argv, so we can read the pointed-to memory without atomics
// or synchronization.
//
// If either ARGC or ARGV is still zero or null, then either there
// really are no arguments, or someone is asking for `args()`
// before initialization has completed, and we return an empty
// list.
let argv = ARGV.load(Ordering::Relaxed);
dbg!(argv);
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
dbg!(argc);
(0..argc)
.map(|i| {
let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
dbg!(&cstr);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
})
.collect()
}
}
I then built and ran it with this modified version of the standard library (RUSTC_BOOTSTRAP=1 cargo build --release -Z build-std --target=x86_64-unknown-linux-gnu
) and got this output:
$ GST_PLUGIN_PATH=$PWD/../target/x86_64-unknown-linux-gnu/release gst-launch-1.0 -v rssinesrc ! autoaudiosink
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:143] argv = 0x00007ffd60a47e88
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:145] argc = 5
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:149] &cstr = "gst-launch-1.0"
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:149] &cstr = "rssinesrc"
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:149] &cstr = "!"
[/home/me/.rustup/toolchains/1.64.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/args.rs:149] &cstr = "autoaudiosink"
Caught SIGSEGV
Spinning. Please run 'gdb gst-launch-1.0 205025' to continue debugging, Ctrl-C to quit, or Ctrl-\ to dump core.
If I understand this correctly that the argument parsing code in gst-launch modifies argv
array and removes the -v
argument. Maybe one of the pointers in argv
is zeroed, or argc
is too long; Either way, it seems the assumptions that the unsafe
code in rust's standard library makes about those two varibles are invalidated, thus causing the segfault. I tried to dig deeper, but I'm not familiar enough with both C and GLib to make much sense of what's going on here.
This seems to be the main
function of gst-launch-1.0
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/7050b00c109e6c404edd50433e4ca7a11a31db78/subprojects/gstreamer/tools/gst-launch.c#L1074
And the parser logic: https://gitlab.gnome.org/GNOME/glib/-/blob/9e2ad88455e422d9b2b6324388bbadabddbf1489/glib/goption.c#L647
I'm unsure of how to fix this; for now, I'll just not use -v
, and remove the call to std::env::args()
from the crate my plugin is depending on.