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
Track implementation for MC/DC #124144
Comments
@rustbot label +A-code-coverage |
The tracking issue should probably include a (brief) definition of MCDC, as otherwise this is untrackable by anyone who does not already know what the issue is for. |
nit on the terminology, but I'd rather say that conditions are boolean expressions that have no logical operator. |
Excellent, that's much better, thank you! The teams every now and then review tracking issues and it is helpful if whoever is participating in the review can understand what the tracking issue is about without any domain expertise (even if only so they can fetch the appropriate subject-matter expert). |
Thanks for correctness! I should have written "binary logical operators". It's a bit different with normal definition because I think treat conditions + unary operators as condition does not lead to different results in MC/DC. |
Upon implementing mcdc for pattern match, I found that decisions here might be confusing. |
I wonder how should let-chains be instrumented. for example: if let (A | B, C) = value && let Some(X | Y) = other && (x || y) {
} Here, I can't decide whether we should insert 1 or 3 MCDC decision records here
Maybe the 3 decisions would be better and easier to do, but I fear this would add a lot of verbosity to the report, and also increase the number of conditions in decisions, which therefore increase the complexity of the testing. What do you think ? |
I'd tend to 3 decisions as it's more clear and easy to be implemented. Besides, if we want to present consistent results in mcdc, we would better take all refutable pattern matching as decisions or not, otherwise we might face paradox like branch coverage in lazy expressions now. |
That makes sense, indeed. Let's go with this strategy then :) Also, I think it would make sense to allow the user to disable pattern matching instrumentation if needed (for example to reduce the binary size if needed). Maybe we could do this with a flag |
Good idea, |
I have a few cleanup steps planned for after #123409/#124255:
|
…ons, r=oli-obk MCDC coverage: support nested decision coverage rust-lang#123409 provided the initial MCDC coverage implementation. As referenced in rust-lang#124144, it does not currently support "nested" decisions, like the following example : ```rust fn nested_if_in_condition(a: bool, b: bool, c: bool) { if a && if b || c { true } else { false } { say("yes"); } else { say("no"); } } ``` Note that there is an if-expression (`if b || c ...`) embedded inside a boolean expression in the decision of an outer if-expression. This PR proposes a workaround for this cases, by introducing a Decision context stack, and by handing several `temporary condition bitmaps` instead of just one. When instrumenting boolean expressions, if the current node is a leaf condition (i.e. not a `||`/`&&` logical operator nor a `!` not operator), we insert a new decision context, such that if there are more boolean expressions inside the condition, they are handled as separate expressions. On the codegen LLVM side, we allocate as many `temp_cond_bitmap`s as necessary to handle the maximum encountered decision depth.
…ons, r=Zalathar MCDC coverage: support nested decision coverage rust-lang#123409 provided the initial MCDC coverage implementation. As referenced in rust-lang#124144, it does not currently support "nested" decisions, like the following example : ```rust fn nested_if_in_condition(a: bool, b: bool, c: bool) { if a && if b || c { true } else { false } { say("yes"); } else { say("no"); } } ``` Note that there is an if-expression (`if b || c ...`) embedded inside a boolean expression in the decision of an outer if-expression. This PR proposes a workaround for this cases, by introducing a Decision context stack, and by handing several `temporary condition bitmaps` instead of just one. When instrumenting boolean expressions, if the current node is a leaf condition (i.e. not a `||`/`&&` logical operator nor a `!` not operator), we insert a new decision context, such that if there are more boolean expressions inside the condition, they are handled as separate expressions. On the codegen LLVM side, we allocate as many `temp_cond_bitmap`s as necessary to handle the maximum encountered decision depth.
Introduction
Modified condition/decision coverage (MC/DC) is a code coverage criterion used widely in safety critical software components and is required by standards such as DO-178B and ISO26262.
Terminology
condition: boolean expressions that have no binary logical operators. For example,
a || b
is not "condition" because it has an or operator whilea==b
is.decision: boolean expressions composed of conditions and binary boolean expressions.
MC/DC requires each condition in a decision is shown to independently affect the outcome of the decision.
e.g Suppose we have code like
Here
(a || b) && c
is a decision anda
,b
,c
are conditions.(a=true, b=false, c=true)
and(a=false, b=false, c=true)
, we saya
can independently affect the decision because the value of decision is changed asa
changes while keepb
andc
unchanged. So that we get 1/3 MC/DC here (1 fora
and 3 fora
,b
,c
).(a=false, b=true, c=true)
and(a=false, b=false, c=false)
also showb
can independently affect the decision because in the later casec
is short-circuited and has no impacts (thus we can view it as same asc=true
). However,c
is not acknowledged due to change ofb
. Plus the two cases before we get 2/3 MC/DC.(a=true,b=false,c=true)
and(a=true,b=false,c=false)
showc
can do the same. By now we get 3/3.Notice that there are duplicate cases, so test cases collection {
(a=true, b=false, c=true)
,(a=false, b=false, c=true)
,(a=false, b=true, c=true)
,(a=false, b=false, c=false)
,(a=true,b=false,c=false)
} is sufficient to prove 3/3 MC/DC.In fact we can use at least n+1 cases to prove 100% MC/DC of decision with n conditions. (In this example, {
(a=true,b=false,c=true)
,(a=false,b=false,c=true)
,(a=false,b=true,c=true)
,(a=true,b=false,c=false)
} is enough)Progress
A basic implementation for MC/DC is filed on #123409 , which has some limits. There are still several cases need to handle:
let val = a || b
. For now this is impacted by branch coverage and work in a different style with certification standards where usually MC/DC is required. To solve this, 124120 is the prerequisite.Draft: Coverage: Add condition coverage #124402
if-let
pattern. Ferrous suggests that refutable pattern matching should be considered as decisions, which sounds certainly reasonable as these are considered as branches too.This depends on support from branch coverage (see 124118).Draft: Support mcdc analysis for pattern matching #124278
Besides, decisions in match guard might still be left to discuss.
if (a || b) || inner_decision(c || d)
Done by MCDC coverage: support nested decision coverage #124255
The text was updated successfully, but these errors were encountered: