-
Notifications
You must be signed in to change notification settings - Fork 276
Boundary value analysis (do not merge) #298
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
Boundary value analysis (do not merge) #298
Conversation
src/goto-instrument/cover.cpp
Outdated
@@ -1069,9 +1070,6 @@ void instrument_cover_goals( | |||
has_prefix(id2string(goto_program.instructions.front().source_location.get_file()), | |||
"<builtin-library-")) | |||
return; | |||
|
|||
const irep_idt coverage_criterion=as_string(criterion); | |||
const irep_idt property_class="coverage"; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you restore this change, please? You have overwritten some commits.
src/goto-instrument/cover.cpp
Outdated
} | ||
|
||
for(std::size_t i=0; i<decisions.size()*2; i++) | ||
i_it++; | ||
} | ||
break; | ||
|
||
|
||
case coverage_criteriont::BOUNDARY: | ||
case coverage_criteriont::MCDC: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make 'boundary-values' and MC/DC independent. One can give two --cover options to get both together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the 'boundary-value-analysis' here is not really independent from the MC/DC criterion. It applies to the test cases generated by MC/DC.
For example, given a the decision 'x<3 && y<=5', three tests will be generated following MC/DC:
- x<3 && y<=5
- x>=3 && y<=5
- x<3 && y>5
The boundary value analysis then applies to each test generated, the 2nd one (similar for the 1st one) will be split into
2.1) x>3 && y<5
2.2) x==3 && y<5
2.3) x>3 && y==5
2.4) x==3 && y==5
Is it possible to
- create a criterion named (let's say) 'MCDC_BOUNDARY'
or 2) add an option 'boundary-values' to --cover and its combination with 'mcdc' triggers the boundary value analysis after normal MC/DC?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go for option 2, I would consider that cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sent the implementation to Lucas. While I only changed several lines of codes, the diff seems to be quite big.
The 'cover.cpp' becomes more complex day by day. Thinking to refactor the coverage codes. A class like 'class coveraget'?
src/goto-instrument/cover.cpp
Outdated
const irep_idt coverage_criterion=as_string(criterion); | ||
const irep_idt property_class="coverage"; | ||
|
||
Forall_goto_program_instructions(i_it, goto_program) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach seems rather inefficient: iterate over all the instructions multiple times? Wouldn't it be possible to turn the criteria into several Booleans and then stick with the previous code that primarily iterates over the instructions? For each instruction, then test, e.g., is_assert() && cover_assertions (with cover_assertions being such a Boolean variable that equals criteria.find(coverage_criteriont::ASSERTION)!=criteria.end().
src/goto-instrument/cover.cpp
Outdated
collect_mcdc_controlling_rec(d, { }, result); | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change necessary?
src/goto-instrument/cover.h
Outdated
const std::set<coverage_criteriont> &criteria); | ||
|
||
// functions for boundary values analysis | ||
std::set<exprt> non_ordered_expr_expansion(const exprt &src); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason for using sets over hash_set_cont?
src/goto-instrument/cover.h
Outdated
std::set<exprt> replacement_and_conjunction( | ||
const std::set<exprt> &replacement_exprs, | ||
const std::vector<exprt> &operands, | ||
const std::size_t i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do all these functions genuinely need to go in the global namespace? Wouldn't it be sufficient to have them as static procedures in the cpp file?
exprt e1(ID_lt); | ||
e1.type().id(src.type().id()); | ||
e1.operands().push_back(src.op0()); | ||
e1.operands().push_back(src.op1()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be simpler to copy the entire expression and replace the id()? That is, do exprt e1(src); e1.id(ID_lt);
} | ||
std::set<exprt> co=replacement_and_conjunction(res, operands, i); | ||
s2.insert(co.begin(), co.end()); | ||
if(res.size()>0) break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if(!res.empty()) break;
(.size() may have linear complexity, empty() is constant time)
} | ||
|
||
// expand negations and non-ordered predicates | ||
while(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid while(true) loops - pull bool changed
out of the loop and explicitly use while(changed)
or while(!changed)
or operands[i].id()==ID_notequal) | ||
{ | ||
res=non_ordered_predicate_expansion(operands[i]); | ||
if(res.size()>0) changed=true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed=!res.empty() || changed;
|
||
bool is_arithmetic_predicate(const exprt &src) | ||
{ | ||
if(src.id()==ID_lt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return src.id()==ID_lt || ...;
src/symex/symex_parse_options.cpp
Outdated
else | ||
{ | ||
error() << "unknown coverage criterion" << eom; | ||
return true; | ||
} | ||
|
||
status() << "Instrumenting coverge goals" << eom; | ||
instrument_cover_goals(symbol_table, goto_model.goto_functions, c); | ||
instrument_cover_goals(symbol_table, goto_model.goto_functions, {c}); | ||
//instrument_cover_goals(symbol_table, goto_model.goto_functions, c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to keep old code, we have version control.
On 11/10/16 10:24 PM, Michael Tautschnig wrote:
I do not like puting them here either. To avoid growing the cover.cpp
Thanks! Going to make changes.
Youcheng Sun |
@tautschnig: Youcheng tried to implement all your comments related to the boundary value analysis. Let us know if there is still something that should be improved. |
src/goto-instrument/cover.cpp
Outdated
|
||
\*******************************************************************/ | ||
|
||
std::set<exprt> non_ordered_predicate_expansion(const exprt &src) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still insist that these should be marked static - yes, the file is way too large and should be chopped up, but that shouldn't be stopping anyone from marking them static now so that later, when splitting up, those people understand what the usage scope is.
src/goto-instrument/cover.cpp
Outdated
|
||
std::set<exprt> non_ordered_predicate_expansion(const exprt &src) | ||
{ | ||
std::set<exprt> result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the return type shouldn't even be a set, but a list: the elements are guaranteed to be unique and lookup is not required.
src/goto-instrument/cover.cpp
Outdated
|
||
std::set<exprt> ordered_negation(const exprt &src) | ||
{ | ||
std::set<exprt> result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above for comments on return type and marking it static.
src/goto-instrument/cover.cpp
Outdated
if(i!=j) | ||
others.push_back(operands[j]); | ||
|
||
others.push_back(y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several problems here:
- This assumes that the operands commute as the new element will be the last one.
- What if operands.size()<=i?
- Repeated push_back without prior reserve() is inefficient.
I would propose:
assert(operands.size()>i);
std::vector<exprt> others(operands);
others[i]=y;
src/goto-instrument/cover.cpp
Outdated
const std::vector<exprt> &operands, | ||
const std::size_t i) | ||
{ | ||
std::set<exprt> result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'm not sure this should be a set - why not a list?
src/goto-instrument/cover.cpp
Outdated
} | ||
if(!changed) s2.insert(x); | ||
} | ||
if(!changed) break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop looks like programming with gotos, except that gotos would at least have the possibility of meaningful labels. If at least there were some comments saying what the individual branches try to achieve. Also, the s2.insert(x) might be replicated and placed with the individual cases to make clear that x isn't lost in all those if(...) without an else case.
src/goto-instrument/cover.cpp
Outdated
if(d.id()==ID_not) d=d.op0(); | ||
if(is_arithmetic_predicate(d)) | ||
{ | ||
auto res=non_ordered_predicate_expansion(d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about non_ordered_predicate_expansion just returns its argument when there was nothing to expand? That would avoid those subsequent if(empty) handling.
src/goto-instrument/cover.cpp
Outdated
@@ -235,8 +528,7 @@ void collect_mcdc_controlling_rec( | |||
std::set<exprt> &result) | |||
{ | |||
// src is conjunction (ID_and) or disjunction (ID_or) | |||
if(src.id()==ID_and || | |||
src.id()==ID_or) | |||
if(src.id()==ID_and || src.id()==ID_or) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why that change is required?
src/goto-instrument/cover.cpp
Outdated
} | ||
return result; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No white-space changes, please.
src/goto-instrument/cover.cpp
Outdated
@@ -741,7 +1002,7 @@ std::map<exprt, signed> values_of_atomic_exprs( | |||
for(auto &c : conditions) | |||
{ | |||
std::set<signed> signs=sign_of_expr(c, e); | |||
if(signs.size()==0) | |||
if(signs.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like those changes, but it would be great if they were in a separate commit or even pull request as the commit message of this one is not going to explain very well why they had been made.
This will now need a rebase. |
I have just talked to @theyoucheng. He'll implement Michael's comments and apply a rebase as suggested by Daniel until 16/12. |
@tautschnig: This week @theyoucheng is expected to work on your comments. What do you think if we break your comments into two parts (with two different pull requests): comments related to the boundary value analysis (BVA) and comments related to the existing cover.cpp implementation? @theyoucheng mentioned that the comments related to the BVA is ok to implement, but most of your comments are related to the existing cover.cpp implementation, which I think it was written by @kroening. |
@lucasccordeiro @theyoucheng It sounds like very good idea to have two pull requests here, even though there will be some management overhead for you. But hopefully the cover.cpp refactoring can be merged rather soon so that the overhead is kept low. |
Thanks, @tautschnig. I have talked to @kroening and @peterschrammel about this PR. @peterschrammel agrees with all your comments. So @theyoucheng is already working on them. Additionally, @peterschrammel also asked me to: (1) Split the cover.cpp into separate files, one for each instrumentation. Only the main loop should be in cover.cpp I'll synchronize with @theyoucheng so that we can have all those comments implemented. |
059dc49
to
28b935d
Compare
@tautschnig: There are several coding style errors if we run cpplint.py over cbmc_parse_options.cpp and symex_parse_options.cpp files. Should we fix all of them or just the ones we have introduced? For cover.cpp and cover.h we believe we have fixed all coding style errors given that we have re-factored that code. I still have to talk to @peterschrammel about splitting the cover.cpp file into separate files, one for each instrumentation. |
I have talked to @thk123 at Diffblue. He told me that there is already a pull request to fix the code guideline for cbmc_parse_options.cpp (see #338 #343). I'm also facing some issues about the errors related to the code guideline, e.g., add space for "+" in expressions like "++it". @thk123 told me that he has already fixed some issues in the cpplint.py script via PR #342. |
Signed-off-by: Lucas Cordeiro <[email protected]>
Updated cover.cpp and cover.h files to fix merge conflicts.
Signed-off-by: Lucas Cordeiro <[email protected]>
Signed-off-by: Lucas Cordeiro <[email protected]>
Signed-off-by: Lucas Cordeiro <[email protected]>
Expand a decision by non_ordered_expr_expansion instead of non_ordered_predicate_expansion. Additionally, remove white space and unnecessary line break.
Two regression test outputs are adjusted, as the order of predicates in the output sometimes differs after the simplification.
Created a class called instrument_cover_goalst that contains methods and atributes related to instrumenting coverage goals
Created methods for assertion, cover, location, branch, condition, decision, and mcdc.
Signed-off-by: Lucas Cordeiro <[email protected]>
…options.cpp Signed-off-by: Lucas Cordeiro <[email protected]>
Signed-off-by: Lucas Cordeiro <[email protected]>
We have created a base class called cover_utils, which contains all attributes and methods used by all coverage analysis (e.g., location, branch, condition, etc). We have then inhereted instrument_cover_goalst and instrument_mcdc_goalst from that base class.
730bdfe
to
aa9696d
Compare
Signed-off-by: Lucas Cordeiro <[email protected]>
Signed-off-by: Lucas Cordeiro <[email protected]>
Signed-off-by: Lucas Cordeiro <[email protected]>
@peterschrammel: I have just split cover.cpp into three separate files. In particular, I have created a base class called "cover_utilst", which contains all common attributes and methods used by all coverage analysis (e.g., location, branch, condition, etc). Thus, I have created the instrument_cover_goalst and instrument_mcdc_goalst classes by inhereting from that base class. If you're happy with this solution, I can replicate this for the other coverage analysis so that we can split cover.cpp into separate files, one for each instrumentation. |
@peterschrammel @lucasccordeiro Does this PR need more changes than a rebase before it can be reviewed in detail again? |
@forejtv: This PR is quite obsolete. We have to check with @peterschrammel whether it is still useful for CBMC since it will require a significant effort to rebase it again, given that I made structural changes to cover.cpp (e.g., breaking the different coverage metrics into separate files). |
…fix/initializer-evs-spreads-to-dynamic-object Fix bug that initializer evs can spread to dynamic objects
Closing since according to the author himself this PR is obsolete. |
No description provided.