# Troubleshooting

As much as we hope everything goes smoothly, sometimes things don't quite work
out of the box. This guide aims to help troubleshoot a wide array of potential
issues!

On Linux the default engine is ptrace so it's always worthwhile trying
`--engine llvm` on Linux if a project doesn't quite work and steps aren't covered
below.

## General Troubleshooting

### Compilation Failures

If your project compiles fine outside of tarpaulin but fails when running
via tarpaulin the issue may be related to dead-code linking. For projects
that link to native libraries `-Clink-dead-code` will cause a compilation
error [rustc issue](https://github.com/rust-lang/rust/issues/64685). To solve
this there is a `--no-dead-code` argument to remove dead code linking. 

Removing dead code linking will cause uncovered functions in your code to
not be present in the debug info meaning they may be completely missed from
coverage. To mitigate this `--engine llvm` should also be used.

### Linker Errors Running Tests

Some libraries may do things like download dependencies into the target
folder for testing and set the `LD_LIBRARY_PATH` causing the tests to pass
when ran via `cargo test`. This will fail with tarpaulin because we use
`cargo test --no-run` internally and then run the tests afterwards. 

To solve this, ensure that you recreate an environment so that you can run your
tests calling the test binary in the target folder directly and not just via
`cargo test`.

### Inaccurate Coverage Results

Tarpaulin builds up a view of the source code coverage by utilising debug
information in the tests and source tree analysis to filter out lines which
don't meaningfully contribute to results but may appear as "coverable" in the
code.

Inaccurate coverage can be caused by:

1. Misleading debug information
2. Language constructs that make source location hard to reason about.
3. Macros

Here are some tips to avoid these issues:

Avoid inlining - this can be a tarpaulin only configuration, but inline
functions won't end up with representative debug information and may be
shown as lines that should be covered. You could do this as so:

```
#[cfg_attr(tarpaulin, inline(never))]
```

With highly generic code unused generics won't be represented in debug
information. To avoid this impacting results tarpaulin aims to reason about
which lines _should_ be in the results. As this uses some manner of heuristics,
minimising generic use can improve results. Although, you shouldn't be shaping
your code to get better coverage results unless you have a regulatory reason to
do so (and then maybe don't consider tarpaulin without reaching out first).

Avoid large amounts of macros or macros with branching behaviour in them.
Unfortunately being overly allowing on macro coverage would make tarpaulin's
coverage statistics less trustworthy and the current approach is it's better
to report too low than too high.

### Doctest Coverage

This is a nightly only feature! So if you're not running in nightly that will
be your first issue.

Retaining the doctests to gain coverage is mildly tricky, the executable
generated uses the location of the doc test to generate the file name and
isn't a clear one-to-one mapping. This means some heuristics have to be used.

There are some steps you can do to avoid clashes in generated file names.

1. Avoid adding doctests in your README or other markdown included like 
`#![doc = include_str!("../README.md")]` 
2. Avoid name overlap if you replace all path separators with `_` so no
files like `src/bar_foo.rs` and `src/bar/foo.rs` 

This would _generally_ not be a big problem, but if there are doc tests which
should panic then tarpaulin has to catch the exit code for the doc test and
ensure that it is not zero to make sure the test pass/fail is reported
correctly and coverage continues on.

### Cannot open libssl.so

Tarpaulin by default will attempt to use a system libssl for uploading coverage
reports or general interfacing with the network. If you have an issue running
tarpaulin due to an error like:

```
cargo-tarpaulin: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
```

It may be solved by installing using the `vendored-openssl` feature like so:

```
cargo install --features vendored-openssl cargo-tarpaulin
```

## Ptrace Engine

### Unix Signals

If your test uses unix signals tarpaulin using ptrace may steal them and cause
tarpaulin to exit with a failure. `--forward-signals` is a useful flag here to
mitigate some of these issues. Also if you use a lot of process spawns
`--follow-exec` may be of use.

Unfortunately, ptrace is a complicated API and signal handling further
complicates it so switching to `--engine llvm` may be the best solution.

### EPERM Operation not Permitted

The ptrace engine needs to use the `personality` syscall to disable ASLR. If
this operation is not allowed then the ptrace engine will fail.

Either use `--engine llvm` or allow the syscall. In docker this would involve
setting the `personality` syscall to `SCMP_ACT_ALLOW` or using
`--seccomp=unconfined`

## LLVM Instrumentation

### Coverage not Collecting from Applications

If a process segfaults or exits with a panic LLVM instrumentation won't write
out the profraw files with coverage data. For tests or applications that do this
(i.e. `should_panic` doctests) you will have to use the ptrace engine or make 
them not panic and find an alternative testing method.

As tests need to exit 0 to pass, this typically only impacts doctests and 
spawned processes, not the actual tests themselves. For spawned processes this
would result in a decrease in coverage.
