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

xd009642 / tarpaulin / #735

17 Mar 2026 03:28AM UTC coverage: 85.243% (-0.3%) from 85.516%
#735

Pull #1830

xd009642
Add process offset as well.
Pull Request #1830: Start abstracting all process things.

95 of 132 new or added lines in 4 files covered. (71.97%)

3 existing lines in 1 file now uncovered.

4835 of 5672 relevant lines covered (85.24%)

246223.31 hits per line

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

51.79
/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::event_source::{EventSource, PtraceEventSource};
5
use crate::process_handling::execute_test;
6
use crate::Config;
7
use crate::TestHandle;
8
use nix::sched::*;
9
use nix::sys::personality;
10
use nix::unistd::*;
11
use std::ffi::{CStr, CString};
12
use std::path::Path;
13
use std::rc::Rc;
14
use std::sync::LazyLock;
15
use tracing::{info, warn};
16

17
static NUM_CPUS: LazyLock<usize> = LazyLock::new(|| num_cpus::get());
114✔
18

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

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

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

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

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

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

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

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

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

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

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

115
    unreachable!();
116
}
117

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

122
    #[test]
123
    fn can_disable_aslr() {
1✔
124
        assert!(is_aslr_enabled());
2✔
125
        disable_aslr().unwrap();
2✔
126
        assert!(!is_aslr_enabled());
2✔
127
    }
128
}
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