llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.78k stars 11.9k forks source link

[llvm-cov][MC/DC][Qualification] Wrong computation of conditions #110090

Open escherle-validas opened 1 month ago

escherle-validas commented 1 month ago

Wrong computation of conditions

Criticality: MEDIUM

In the attached example there are 10 conditions, however the tool a) splits up the entire decision in 2 separate decisions with 3 conditions each (for C++) and b) computes only 3 conditions (for Rust). Also the specified "positions" are wrong, i.e. do not point to the right places. Furthermore it is critical, that Rust and C++ differ.

Rust: columns_of_conditions_rust

Source code and generated reports: Test_000010.zip

C++ columns_of_conditions_cpp

Source code and generated reports: Test_000010.zip

escherle-validas commented 1 week ago

Since we have no reply from you yet, I would like to ask for a status update for this issue. Are there any plans how this will be handled?

Lambdaris commented 1 week ago

Not sure which version of rust you used. I check it on the latest nightly rustc and it shows

    2|      1|    if ((false && true) && (false == (v2 == false))) == ((v0 == v2) || (v0 || v0 == v2)) {
  ------------------
  |---> MC/DC Decision Region (2:8) to (2:53)
  |
  |  Number of Conditions: 3
  |     Condition C1 --> (2:10)
  |     Condition C2 --> (2:19)
  |     Condition C3 --> (2:28)
  |
  |  Executed MC/DC Test Vectors:
  |
  |     C1, C2, C3    Result
  |  1 { F,  C,  C  = F      }
  |
  |  C1-Pair: not covered
  |  C2-Pair: constant folded
  |  C3-Pair: constant folded
  |  MC/DC Coverage for Decision: 0.00%
  |
  |---> MC/DC Decision Region (2:57) to (2:89)
  |
  |  Number of Conditions: 3
  |     Condition C1 --> (2:58)
  |     Condition C2 --> (2:73)
  |     Condition C3 --> (2:79)
  |
  |  Executed MC/DC Test Vectors:
  |
  |     C1, C2, C3    Result
  |  1 { F,  T,  -  = T      }
  |
  |  C1-Pair: not covered
  |  C2-Pair: not covered
  |  C3-Pair: not covered
  |  MC/DC Coverage for Decision: 0.00%
  |
  ------------------
    3|      0|        println!("pass");
    4|      1|    }
    5|      1|}
    6|       |
    7|      1|fn main() {
    8|      1|    direct(true, false);
    9|      1|}

It's because rust's "nested decision" mechanism.

As you have checked, "==" and "!=" are not considered as logical operations by rust for now.

So rust first sees the whole statement, which is in form of a == b, and takes it as a decision with only one condition. Let's say it's D1.

Then rust looks into the inner statements, and finds that a is a decision (false && true) && (false == (v2 == false)), which is composed of 3 conditions: the first false, the first true and false == (v2 == false). Note these conditions are organized with only &&. Let's write this decision as D2.

As for b part, it is also a decision (v0 == v2) || (v0 || v0 == v2), with 3 conditions: v0 == v2, v0 and v0==v2. Let's say the decision of b is D3.

In rust's sight, D2 and D3 are nested in D1. But D1 only contains one condition, so it is ignored by mcdc checker. Rust mcdc always ignores decisions with only one condition because it's totally equivalent to branch coverage (Actually we can even prove it's true for decisions with two conditions, but not so clear). Hence only D2 and D3 left and rust shows results as above.

The result is also not right. The reason is the constant issue clarified at #109940 .

Thus the last issue is "==" and "!=" are not recognized as logical operations, same as #109947 .