• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xd009642 / tarpaulin / #679

19 Oct 2025 02:09PM UTC coverage: 75.356% (-0.2%) from 75.524%
#679

push

web-flow
Fix a bunch of cargo config stuff... (#1784)

* Fix a bunch of cargo config stuff...

So the previous way cargo-tarpaulin handled the config files was a bit
lazy. It only looked in the project directory and the home directory. Now I
follow the actual compiler behaviour and go from project to root
looking for config files then the one in the home directory merging
things as we go...

This also grabs the env vars from the config files and applies them when
the metadata is gathered, project built and project ran!

* Tests compile now

* Don't roll my own config resolution

* fmt

* Add in config env test

* Oops

* Bump version and changelog

68 of 83 new or added lines in 7 files covered. (81.93%)

1 existing line in 1 file now uncovered.

3920 of 5202 relevant lines covered (75.36%)

129605.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.15
/src/process_handling/linux.rs
1
use crate::cargo::{CargoConfigFields, TestBinary};
2
use crate::config::types::Mode;
3
use crate::errors::*;
4
use crate::process_handling::execute_test;
5
use crate::ptrace_control::*;
6
use crate::Config;
7
use crate::TestHandle;
8
use lazy_static::lazy_static;
9
use nix::sched::*;
10
use nix::sys::personality;
11
use nix::unistd::*;
12
use std::ffi::{CStr, CString};
13
use std::path::Path;
14
use std::rc::Rc;
15
use tracing::{info, warn};
16

17
lazy_static! {
18
    static ref NUM_CPUS: usize = num_cpus::get();
19
}
20

21
/// Returns the coverage statistics for a test executable in the given workspace
22
pub fn get_test_coverage(
184✔
23
    test: &TestBinary,
24
    config: &Config,
25
    cargo_config: Rc<CargoConfigFields>,
26
    ignored: bool,
27
) -> Result<Option<TestHandle>, RunError> {
28
    if !test.path().exists() {
184✔
29
        warn!("Test at {} doesn't exist", test.path().display());
×
30
        return Ok(None);
×
31
    }
32

33
    // Solves CI issue when fixing #953 and #966 in PR #962
34
    let threads = if config.follow_exec { 1 } else { *NUM_CPUS };
552✔
35

36
    if let Err(e) = limit_affinity() {
184✔
37
        warn!("Failed to set processor affinity {}", e);
×
38
    }
39

40
    unsafe {
41
        match fork() {
184✔
42
            Ok(ForkResult::Parent { child }) => Ok(Some(TestHandle::Id(child))),
184✔
43
            Ok(ForkResult::Child) => {
44
                let bin_type = match config.command {
×
45
                    Mode::Test => "test",
×
46
                    Mode::Build => "binary",
×
47
                };
48
                info!("Launching {}", bin_type);
×
NEW
49
                execute_test(test, &[], ignored, config, cargo_config, Some(threads))?;
×
50
                Ok(None)
×
51
            }
52
            Err(err) => Err(RunError::TestCoverage(format!(
×
53
                "Failed to run test {}, Error: {}",
×
54
                test.path().display(),
×
55
                err
×
56
            ))),
57
        }
58
    }
59
}
60

61
fn disable_aslr() -> nix::Result<()> {
1✔
62
    let this = personality::get()?;
2✔
63
    personality::set(this | personality::Persona::ADDR_NO_RANDOMIZE).map(|_| ())
64
}
65

66
fn is_aslr_enabled() -> bool {
2✔
67
    !personality::get()
2✔
68
        .map(|x| x.contains(personality::Persona::ADDR_NO_RANDOMIZE))
6✔
69
        .unwrap_or(true)
2✔
70
}
71

72
pub fn limit_affinity() -> nix::Result<()> {
184✔
73
    let this = Pid::this();
368✔
74
    // Get current affinity to be able to limit the cores to one of
75
    // those already in the affinity mask.
76
    let affinity = sched_getaffinity(this)?;
552✔
77
    let mut selected_cpu = 0;
×
78
    for i in 0..CpuSet::count() {
184✔
79
        if affinity.is_set(i)? {
552✔
80
            selected_cpu = i;
184✔
81
            break;
×
82
        }
83
    }
84
    let mut cpu_set = CpuSet::new();
184✔
85
    cpu_set.set(selected_cpu)?;
×
86
    sched_setaffinity(this, &cpu_set)
184✔
87
}
88

89
pub fn execute(
×
90
    test: &Path,
91
    argv: &[String],
92
    envar: &[(String, String)],
93
) -> Result<TestHandle, RunError> {
94
    let program = CString::new(test.display().to_string()).unwrap_or_default();
×
95
    if is_aslr_enabled() {
×
96
        disable_aslr().map_err(|e| RunError::TestRuntime(format!("ASLR disable failed: {e}")))?;
×
97
    }
98
    request_trace().map_err(|e| RunError::Trace(e.to_string()))?;
×
99

100
    let envar = envar
×
101
        .iter()
102
        .map(|(k, v)| CString::new(format!("{k}={v}").as_str()).unwrap_or_default())
×
103
        .collect::<Vec<CString>>();
104

105
    let argv = argv
×
106
        .iter()
107
        .map(|x| CString::new(x.as_str()).unwrap_or_default())
×
108
        .collect::<Vec<CString>>();
109

110
    let arg_ref = argv.iter().map(AsRef::as_ref).collect::<Vec<&CStr>>();
×
111
    let env_ref = envar.iter().map(AsRef::as_ref).collect::<Vec<&CStr>>();
×
112
    execve(&program, &arg_ref, &env_ref).map_err(|_| RunError::Internal)?;
×
113

114
    unreachable!();
115
}
116

117
#[cfg(test)]
118
mod tests {
119
    use super::*;
120

121
    #[test]
122
    fn can_disable_aslr() {
1✔
123
        assert!(is_aslr_enabled());
2✔
124
        disable_aslr().unwrap();
2✔
125
        assert!(!is_aslr_enabled());
2✔
126
    }
127
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc