Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions sometimes disappear from coverage under MIR opts +Inline,+ConstProp #117012

Closed
Zalathar opened this issue Oct 21, 2023 · 6 comments · Fixed by #117123
Closed

Functions sometimes disappear from coverage under MIR opts +Inline,+ConstProp #117012

Zalathar opened this issue Oct 21, 2023 · 6 comments · Fixed by #117123
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage)

Comments

@Zalathar
Copy link
Contributor

(Note that this is almost certainly a bug in coverage, not in MIR opts.)

Consider this coverage report, produced by x test run-coverage --bless on a new test file:

   LL|       |#![feature(coverage_attribute)]
   LL|       |// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=1 -Zmir-enable-passes=+Inline,+ConstProp
   LL|       |
   LL|      8|#[derive(Debug, PartialEq, Eq)]
   LL|       |struct Foo(u32);
   LL|       |
   LL|      1|fn eq_good() {
   LL|      1|    assert_eq!(Foo(1), Foo(1));
   LL|      1|}
   LL|       |
   LL|      1|fn eq_good_message() {
   LL|      1|    assert_eq!(Foo(1), Foo(1), "message");
                                             ^0
   LL|      1|}
   LL|       |
   LL|       |fn ne_good() {
   LL|       |    assert_ne!(Foo(1), Foo(3));
   LL|       |}
   LL|       |
   LL|       |fn ne_good_message() {
   LL|       |    assert_ne!(Foo(1), Foo(3), "message");
   LL|       |}
   LL|       |
   LL|      1|fn eq_bad() {
   LL|      1|    assert_eq!(Foo(1), Foo(3));
   LL|      0|}
   LL|       |
   LL|       |fn eq_bad_message() {
   LL|       |    assert_eq!(Foo(1), Foo(3), "message");
   LL|       |}
   LL|       |
   LL|      1|fn ne_bad() {
   LL|      1|    assert_ne!(Foo(1), Foo(1));
   LL|      0|}
   LL|       |
   LL|      1|fn ne_bad_message() {
   LL|      1|    assert_ne!(Foo(1), Foo(1), "message");
   LL|      0|}
   LL|       |
   LL|       |#[coverage(off)]
   LL|       |fn main() {
   LL|       |    eq_good();
   LL|       |    eq_good_message();
   LL|       |    ne_good();
   LL|       |    ne_good_message();
   LL|       |
   LL|       |    let _ = std::panic::catch_unwind(eq_bad);
   LL|       |    let _ = std::panic::catch_unwind(eq_bad_message);
   LL|       |    let _ = std::panic::catch_unwind(ne_bad);
   LL|       |    let _ = std::panic::catch_unwind(ne_bad_message);
   LL|       |}

All of these functions should look roughly the same in the coverage report, but instead three of them (ne_good, ne_good_message, eq_bad_message) are completely missing, despite the fact that they are all executed.

The problem also occurs under -Copt-level=2 or -Zmir-opt-level=3, but I narrowed it down to just -Zmir-opt-level=1 plus the Inline and ConstProp passes. If I reduce the MIR opt level to 0, or remove either of those passes, I get the expected output where all functions are reported correctly.

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 21, 2023
@Zalathar
Copy link
Contributor Author

@rustbot label +A-code-coverage

@rustbot rustbot added the A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) label Oct 21, 2023
@Zalathar
Copy link
Contributor Author

Mysteriously, if I run the same test file in tests/coverage-map, the mappings seem fine.

So far I haven't tracked down the precise differences between affected binaries and unaffected binaries.

@Zalathar
Copy link
Contributor Author

The above test file was the result of reducing a much more complicated test file (tests/run-coverage/issue-84561.rs), in which the entire test3 function disappears from coverage.

Unlike my simplified examples above, that test3 function contains a bunch of print statements and also is responsible for panicking out of the entire program, which seems to rule out problems based entirely on small functions with no other effects.

@saethlin saethlin removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 22, 2023
@Zalathar

This comment was marked as outdated.

@Zalathar
Copy link
Contributor Author

OK, I think this is caused by the fact that map_data will emit expression operands containing counters that are not present in counters_seen.

@Zalathar
Copy link
Contributor Author

Because I wasn't seeing anything missing/suspicious in the .cov-map files, I figured this might have something to do with llvm-cov.

I was able to apply printf debugging by:

  • Adding #include <iostream> and std::cout << ... << std::endl; to the LLVM source to print extra information, which would then appear in the .cov-map files as part of the tool output.
  • rm build/aarch64-apple-darwin/llvm/llvm-finished-building ; x build llvm to tell the build system to actually rebuild LLVM with my changes.

@bors bors closed this as completed in 6b78377 Oct 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants