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

xd009642 / tarpaulin / #680

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

push

xd009642
Release 0.34.0

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%)

131250.96 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