Repository: rust
Issue: Mac lldb debuginfo behavior differs based on abs/rel input source path (?!)
Labels: A-testsuite,A-debuginfo,P-low,T-compiler,C-bug

I am observing varying behavior on my Mac depending on whether the input source files to `rustc` are denoted via an absolute source path or a relative one.

The test where I am seeing varying behavior is the `cross-crate-spans.rs` debuginfo test: https://github.com/rust-lang/rust/blob/master/src/test/debuginfo/cross-crate-spans.rs

In a nutshell: when I need to make a breakpoint for a line in the auxiliary crate (the `auxiliary/cross_crate_spans.rs` in the test in question), I am seeing the breakpoint get hit twice (as expected) when I use a relative paths, but the breakpoint gets hit only once when I use absolute paths to compile the same input files.

----

I have made a shell script to establish the context for the problem:

```sh
set -e
# set -x

RUSTC=rustc

# We'll set up and run the test in an isolated directory just to be safe.

# (Note: needs to be an absolute path for the rest of the script to make sense...)
WORKING_DIR=/tmp/work
mkdir -p $WORKING_DIR
cd $WORKING_DIR

# The behavior we observe will vary depending on the value of
# `$SRC_DIR`. The bad behavior seems to arise whenever SRC_DIR is an
# absolute directory (i.e. whenever it leads with the '/' character.)

case $1 in
     abs) SRC1_DIR=$WORKING_DIR/abs/source ; echo "Aux in absolute source path: $SRC1_DIR" ;;
     rel) SRC1_DIR=rel/source ; echo "Aux in relative source path: $SRC1_DIR" ;;
     *) echo "You need to pass 'abs' or 'rel' as first input to script."; exit 1;
esac

case $2 in
     abs) SRC2_DIR=$WORKING_DIR/abs/source ; echo "Main in absolute source path: $SRC2_DIR" ;;
     # (switching to the below fixes things on my host system.)
     rel) SRC2_DIR=rel/source ; echo "Main in relative source path: $SRC2_DIR" ;;
     *) echo "You need to pass 'abs' or 'rel' as second input to script."; exit 1;
esac

mkdir -p $SRC1_DIR
mkdir -p $SRC2_DIR

# (I renamed the aux file because the dash/underscore differentiating
# convention drove me crazy. However, I have observed that reproducing
# tne bug *also* is sensitive to maintaining the specific filename
# `cross-crate-spans.rs` for the main file. Perhaps there is something
# with how we pun dash and underscore when inferring crate names from
# file names?)

AUX_FILE=$SRC1_DIR/aux.rs
MAIN_FILE=$SRC2_DIR/cross-crate-spans.rs

# Move the files into the source area. (You don't have to use `curl`;
# you can just copy it from your own repository...)

curl -s -o $AUX_FILE -O https://raw.githubusercontent.com/rust-lang/rust/8b1941a7831d715e36a414668a0b23146ff9cc2c/src/test/debuginfo/auxiliary/cross_crate_spans.rs
curl -s -o $MAIN_FILE -O https://raw.githubusercontent.com/rust-lang/rust/8b1941a7831d715e36a414668a0b23146ff9cc2c/src/test/debuginfo/cross-crate-spans.rs

LIB_DIR=$WORKING_DIR/libs

mkdir -p $LIB_DIR

MAIN_BIN=cross-crate-spans

# (Show how the compiler is being invoked in each case.)
set -x

$RUSTC -C opt-level=0 -g $AUX_FILE --crate-name cross_crate_spans --out-dir $LIB_DIR
$RUSTC -C opt-level=0 -g $MAIN_FILE -L $LIB_DIR -C prefer-dynamic -C rpath -o $MAIN_BIN
# $RUSTC -C opt-level=0 -g $MAIN_FILE -L $LIB_DIR -o $MAIN_BIN

lldb $MAIN_BIN
```

----

After invoking the above script (e.g. via `sh /tmp/script abs abs`), you then interact with `lldb` to finish reproducing the bug.

```
% rm -rf /tmp/work/ && sh /tmp/script rel rel
Aux in relative source path: rel/source
Main in relative source path: rel/source
+ rustc -C opt-level=0 -g rel/source/aux.rs --crate-name cross_crate_spans --out-dir /tmp/work/libs
+ rustc -C opt-level=0 -g rel/source/cross-crate-spans.rs -L /tmp/work/libs -C prefer-dynamic -C rpath -o cross-crate-spans
+ lldb cross-crate-spans
(lldb) target create "cross-crate-spans"
Current executable set to 'cross-crate-spans' (x86_64).
(lldb) b aux.rs:24
Breakpoint 1: 2 locations.
(lldb) r
Process 4893 launched: '/private/tmp/work/cross-crate-spans' (x86_64)
Process 4893 stopped
* thread #1: tid = 0xad2057, 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
    frame #0: 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4893 resuming
Process 4893 stopped
* thread #1: tid = 0xad2057, 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4893 resuming
(lldb) Process 4893 exited with status = 0 (0x00000000) 
(lldb) q
% rm -rf /tmp/work/ && sh /tmp/script rel abs
Aux in relative source path: rel/source
Main in absolute source path: /tmp/work/abs/source
+ rustc -C opt-level=0 -g rel/source/aux.rs --crate-name cross_crate_spans --out-dir /tmp/work/libs
+ rustc -C opt-level=0 -g /tmp/work/abs/source/cross-crate-spans.rs -L /tmp/work/libs -C prefer-dynamic -C rpath -o cross-crate-spans
+ lldb cross-crate-spans
(lldb) target create "cross-crate-spans"
Current executable set to 'cross-crate-spans' (x86_64).
(lldb) b aux.rs:24
Breakpoint 1: 2 locations.
(lldb) r
Process 4913 launched: '/private/tmp/work/cross-crate-spans' (x86_64)
Process 4913 stopped
* thread #1: tid = 0xad20ff, 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
    frame #0: 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4913 resuming
Process 4913 stopped
* thread #1: tid = 0xad20ff, 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4913 resuming
(lldb) Process 4913 exited with status = 0 (0x00000000) 
(lldb) q
% rm -rf /tmp/work/ && sh /tmp/script abs rel
Aux in absolute source path: /tmp/work/abs/source
Main in relative source path: rel/source
+ rustc -C opt-level=0 -g /tmp/work/abs/source/aux.rs --crate-name cross_crate_spans --out-dir /tmp/work/libs
+ rustc -C opt-level=0 -g rel/source/cross-crate-spans.rs -L /tmp/work/libs -C prefer-dynamic -C rpath -o cross-crate-spans
+ lldb cross-crate-spans
(lldb) target create "cross-crate-spans"
Current executable set to 'cross-crate-spans' (x86_64).
(lldb) b aux.rs:24
Breakpoint 1: 2 locations.
(lldb) r
Process 4933 launched: '/private/tmp/work/cross-crate-spans' (x86_64)
Process 4933 stopped
* thread #1: tid = 0xad2163, 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
    frame #0: 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4933 resuming
Process 4933 stopped
* thread #1: tid = 0xad2163, 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000b4f cross-crate-spans`cross_crate_spans::generic_function<i16>(val=1212) + 127 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4933 resuming
(lldb) Process 4933 exited with status = 0 (0x00000000) 
(lldb) q
% rm -rf /tmp/work/ && sh /tmp/script abs abs
Aux in absolute source path: /tmp/work/abs/source
Main in absolute source path: /tmp/work/abs/source
+ rustc -C opt-level=0 -g /tmp/work/abs/source/aux.rs --crate-name cross_crate_spans --out-dir /tmp/work/libs
+ rustc -C opt-level=0 -g /tmp/work/abs/source/cross-crate-spans.rs -L /tmp/work/libs -C prefer-dynamic -C rpath -o cross-crate-spans
+ lldb cross-crate-spans
(lldb) target create "cross-crate-spans"
Current executable set to 'cross-crate-spans' (x86_64).
(lldb) b aux.rs:24
Breakpoint 1: 2 locations.
(lldb) r
Process 4955 launched: '/private/tmp/work/cross-crate-spans' (x86_64)
Process 4955 stopped
* thread #1: tid = 0xad21fe, 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000c43 cross-crate-spans`cross_crate_spans::generic_function<u32>(val=17) + 115 at aux.rs:24
   21  	    let result = (val.clone(), val.clone());
   22  	    let a_variable: u32 = 123456789;
   23  	    let another_variable: f64 = 123456789.5;
-> 24  	    zzz();
   25  	    result
   26  	}
   27  	
(lldb) c
Process 4955 resuming
(lldb) Process 4955 exited with status = 0 (0x00000000) 
(lldb) q
% 
```

The transcript above shows that the number of times we hit the breakpoint varies depending on how the source file path was provided.

----

The results are as follows when you vary the absolute/relative nature of each of the two source inputs in the script. (For some period of time, I thought I was observing that problem occurred just based on the main input, but by the time I firmed up the script above, I no longer was seeing that: I had to pass both the aux and the main input as absolute paths in order to reproduce the bug.)

| Aux Input  | Main Input | Breakpoint Hit Count | Expected Result?
| --- | --- | --- | --- |
| rel | rel | 2 | (good)
| rel | abs | 2 | (good)
| abs | rel | 2 | (good)
| abs | abs | 1 | *bad*

----

One more observation: By chance, I decided while looking into this to also try varying the input file names. This led to a new bit of data: reproducing the bug requires the main file keep the source `cross-crate-spans.rs` (and do not pass a `--crate-name` argument to it).
 * If you rename it to `main.rs` (and do not otherwise muck with its crate name), the bug will not reproduce.
 * If you rename it to `main.rs` but also pass `--crate-name cross_crate_spans` (the crate name derived from "cross-crate-spans.rs") when compiling `main.rs`, then the bug *will* reproduce.
 * This leads me to wonder: Is the real bug here that we are blithely allowing multiple crates with the same name to be linked together, and even treating it like a scenario that needs to be part to our *test suite*?
----

My `lldb` reports that it is version `lldb-360.1.70`, and my Xcode (according to `xcodebuild`) is Xcode 8.2.1, Build version 8C1002.