Coverage corrupted by forking in continuous mode
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
I'm getting lines that report >1844*10^16 hits surrounded by lines that are only hit 50 times. And a bunch of lines are reported as not getting hit at all despite every path to the following lines (which are marked as hit) needing to go through those lines. This is with `LLVM_PROFILE_FILE="%m_%p%c.profraw"` and passing `-C instrument-coverage -Cllvm-args=-runtime-counter-relocation=true` to rustc. I need to use continuous mode to ensure lines between a fork and an exec get marked as hit rather than the buffered profile data getting lost.
With continuous mode
```
91 : // SAFETY: There should be no other threads at this point.
92 50 : let ForkResult::Parent(command_pid) = unsafe { fork() }.map_err(|err| {
93 0 : dev_warn!("unable to fork command process: {err}");
94 0 : err
95 0 : })?
96 : else {
97 50 : drop(errpipe_rx);
98 :
99 : // FIXME (ogsudo): Do any additional configuration that needs to be run after `fork` but before `exec`
100 50 : let command_pid = ProcessId::new(std::process::id() as i32);
101 :
102 50 : setpgid(ProcessId::new(0), command_pid).ok();
103 :
104 : // Wait for the monitor to set us as the foreground group for the pty if we are in the
105 : // foreground.
106 50 : if foreground {
107 365 : while !pty_follower.tcgetpgrp().is_ok_and(|pid| pid == command_pid) {
108 340 : std::thread::yield_now();
109 340 : }
110 25 : }
111 :
112 : // Done with the pty follower.
113 50 : drop(pty_follower);
114 :
115 50 : exec_command(command, original_set, original_signals, errpipe_tx)
116 : };
117 :
118 : // Send the command's PID to the parent.
119 >1844*10^16 : if let Err(err) = backchannel.send(&ParentMessage::CommandPid(command_pid)) {
120 >1844*10^16 : dev_warn!("cannot send command PID to parent: {err}");
121 50 : }
122 :
123 0 : let mut registry = EventRegistry::new();
124 :
125 0 : let mut closure = MonitorClosure::new(
126 0 : command_pid,
127 0 : pty_follower,
128 0 : errpipe_rx,
129 0 : backchannel,
130 0 : &mut registry,
131 0 : &mut original_signals,
132 0 : )?;
133 :
134 : // Restore the signal mask now that the handlers have been setup.
135 0 : if let Some(set) = original_set {
136 >1844*10^16 : if let Err(err) = set.set_mask() {
137 >1844*10^16 : dev_warn!("cannot restore signal mask: {err}");
138 50 : }
139 0 : }
```
Without continuous mode
```
91 : // SAFETY: There should be no other threads at this point.
92 50 : let ForkResult::Parent(command_pid) = unsafe { fork() }.map_err(|err| {
93 0 : dev_warn!("unable to fork command process: {err}");
94 0 : err
95 0 : })?
96 : else {
97 0 : drop(errpipe_rx);
98 :
99 : // FIXME (ogsudo): Do any additional configuration that needs to be run after `fork` but before `exec`
100 0 : let command_pid = ProcessId::new(std::process::id() as i32);
101 :
102 0 : setpgid(ProcessId::new(0), command_pid).ok();
103 :
104 : // Wait for the monitor to set us as the foreground group for the pty if we are in the
105 : // foreground.
106 0 : if foreground {
107 0 : while !pty_follower.tcgetpgrp().is_ok_and(|pid| pid == command_pid) {
108 0 : std::thread::yield_now();
109 0 : }
110 0 : }
111 :
112 : // Done with the pty follower.
113 0 : drop(pty_follower);
114 :
115 0 : exec_command(command, original_set, original_signals, errpipe_tx)
116 : };
117 :
118 : // Send the command's PID to the parent.
119 50 : if let Err(err) = backchannel.send(&ParentMessage::CommandPid(command_pid)) {
120 0 : dev_warn!("cannot send command PID to parent: {err}");
121 50 : }
122 :
123 50 : let mut registry = EventRegistry::new();
124 :
125 50 : let mut closure = MonitorClosure::new(
126 50 : command_pid,
127 50 : pty_follower,
128 50 : errpipe_rx,
129 50 : backchannel,
130 50 : &mut registry,
131 50 : &mut original_signals,
132 0 : )?;
133 :
134 : // Restore the signal mask now that the handlers have been setup.
135 50 : if let Some(set) = original_set {
136 50 : if let Err(err) = set.set_mask() {
137 0 : dev_warn!("cannot restore signal mask: {err}");
138 50 : }
139 0 : }
```
Contributor guide
Research direction
Reproduce the report with rustc using `-C instrument-coverage`, `-Cllvm-args=-runtime-counter-relocation=true`, and `LLVM_PROFILE_FILE="%m_%p%c.profraw"` around the shown fork/exec path. Compare continuous and non-continuous coverage output. Done means continuous mode no longer produces enormous counters or misses lines executed between fork and exec.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100