Weird 'nonlocal' segfault with docopt

Hi!

I have been scratching my head with a weird segfault while using the docopt crate. The code is below (or at https://github.com/rekka/docopt_test). To summarize, when parsing an invalid command line input, the program segfaults instead of printing the error message. But this does not happen when I don't use struct Args from lib.rs but from main.rs, or if I change the order of the struct fields! I have no idea whose bug this is so I am not even sure where to report it.

First my compiler (I'm on a Mac).

$ rustc --version && cargo --version                              
rustc 1.10.0 (cfcb716cf 2016-07-03)
cargo 0.11.0-nightly (259324c 2016-05-20)

Now the code. Clone from https://github.com/rekka/docopt_test.

File main.rs

extern crate docopt;
extern crate rustc_serialize;
extern crate docopt_test;

const USAGE: &'static str = "
Test

Usage:
  test [options] [<test>]

Options:
  -n=INT                Integer
";

#[derive(Debug, RustcDecodable)]
pub struct Args {
    arg_test: Option<String>,
    flag_n: Option<usize>,
}

fn main() {
    let args: docopt_test::Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    println!("{:?}", args.flag_n);
}

file lib.rs

extern crate rustc_serialize;

#[derive(Debug, RustcDecodable)]
pub struct Args {
    pub arg_test: Option<String>,
    pub flag_n: Option<usize>,
}

Compiling this and running with invalid input segfaults:

$ cargo build && target/debug/docopt_test -nm                        
[1]    88206 segmentation fault  target/debug/docopt_test -nm

Other inputs are reported properly:

$ cargo build && target/debug/docopt_test -n                       
Expected argument for flag '-n' but reached end of arguments.

Usage:
  test [options] [<test>]
$ cargo build && target/debug/docopt_test -n8                    
Some(8)

But if I use the local struct Args by changing the docopt call to

    let args: Args = docopt::Docopt::new(USAGE)

or just reorder the fields in docopt_test::Args like so

pub struct Args {
    pub flag_n: Option<usize>,
    pub arg_test: Option<String>,
}

the program yields the correct output:

$ cargo build && target/debug/docopt_test -nm  
...               
Could not decode 'm' to usize for '-n'.

The docopt crate does not seem to have any unsafe code. What is causing this?

Any tips are greatly appreciated!

This seems very bad; you should file a bug!

Might be this bug: https://github.com/rust-lang-nursery/rustc-serialize/issues/154 and https://github.com/rust-lang/rust/issues/34592 --- which looks to have been fixed a few days ago.

Yes, you are right! Thanks for the tip, it didn't occur to me that this is a compiler bug. Just tried this with rustup, works on nightly-2016-07-08, segfaults on nightly-2016-07-07.

1 Like