Skip to content

Fix local static variables detection in assigns clauses #6447

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

Merged

Conversation

remi-delmas-3000
Copy link
Collaborator

@remi-delmas-3000 remi-delmas-3000 commented Nov 8, 2021

Function contracts instrumentation:

  1. Use the call graph of the function to detect local static variables declared in the functions it calls.

Other changes:

  1. subfunction call inlining was moved from code_contractst::check_frame_conditions to code_contractst::check_frame_conditions_function.
  2. Recursive functions are now detected during inlining and cause an INVARIANT violation
  3. Function pointers are now detected during call graph construction and cause a PRECONDITION violation
  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@remi-delmas-3000 remi-delmas-3000 added aws Bugs or features of importance to AWS CBMC users aws-high labels Nov 8, 2021
@remi-delmas-3000 remi-delmas-3000 changed the title Fixes local static variables detection. Fix local static variables detection in assigns clause checking instrumentation Nov 8, 2021
@@ -861,7 +861,7 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
for(const auto &sym_pair : symbol_table)
{
const auto &sym = sym_pair.second;
if(sym.is_static_lifetime && sym.location.get_function() == function)
if(sym.is_static_lifetime && !sym.location.get_function().empty())
Copy link
Contributor

@SaswatPadhi SaswatPadhi Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this create CARs for ALL static local variables, like beyond the current function on which contracts are checked and its subfunction calls?

It might have a significant perf impact if lots of unrelated functions also introduce static local variables, because we'll add their CARs unnecessarily to the write set and check every assignment against them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth fixing the inlining routine instead. Inlined static locals should just behave as static locals within the caller. It seems weird and inconsistent to have the function body inlined into a caller but be mutating a static local that's tagged with a different function name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.
Since all sub-function calls are inlined for contract checking, a better solution would be to detect static locals used in the body of the function under analysis rather than at the symbol table level.

@remi-delmas-3000
Copy link
Collaborator Author

remi-delmas-3000 commented Nov 8, 2021

Updated to a better solution is to detect static locals used in the body of the function under analysis rather than at the symbol table level.

@codecov
Copy link

codecov bot commented Nov 8, 2021

Codecov Report

Merging #6447 (59d15d6) into develop (c13e416) will decrease coverage by 0.02%.
The diff coverage is 100.00%.

❗ Current head 59d15d6 differs from pull request most recent head 5fb8ee5. Consider uploading reports for the commit 5fb8ee5 to get more accurate results
Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #6447      +/-   ##
===========================================
- Coverage    76.04%   76.01%   -0.03%     
===========================================
  Files         1546     1527      -19     
  Lines       165543   164487    -1056     
===========================================
- Hits        125885   125035     -850     
+ Misses       39658    39452     -206     
Impacted Files Coverage Δ
src/goto-instrument/contracts/contracts.h 100.00% <ø> (ø)
src/goto-instrument/contracts/contracts.cpp 96.27% <100.00%> (-0.83%) ⬇️
...rc/solvers/smt2_incremental/smt_solver_process.cpp 25.00% <0.00%> (-49.08%) ⬇️
src/solvers/smt2_incremental/smt_solver_process.h 66.66% <0.00%> (-33.34%) ⬇️
src/util/pointer_predicates.cpp 71.60% <0.00%> (-21.95%) ⬇️
unit/solvers/smt2/smt2irep.cpp 83.09% <0.00%> (-16.91%) ⬇️
...ncremental/smt2_incremental_decision_procedure.cpp 78.43% <0.00%> (-11.26%) ⬇️
src/util/piped_process.cpp 76.92% <0.00%> (-3.85%) ⬇️
src/goto-symex/symex_function_call.cpp 93.18% <0.00%> (-2.28%) ⬇️
src/goto-symex/ssa_step.cpp 79.31% <0.00%> (-2.07%) ⬇️
... and 69 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 40fd86b...5fb8ee5. Read the comment docs.

Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only minor requests.

@@ -0,0 +1,14 @@
CORE
main.c
--enforce-contract bar _ --pointer-primitive-check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need --pointer-primitive-check here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there an underscore here (after bar)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this underscore separates two groups of options , the first group is passed to goto-instrument to perform the contract instrumentation, and the second set is passed to cbmc to analyse the instrumented contracts.

@feliperodri feliperodri added the Code Contracts Function and loop contracts label Nov 10, 2021
Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there.

Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo a few minor comments.

@@ -0,0 +1,14 @@
CORE
main.c
--enforce-contract bar _ --pointer-primitive-check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Comment on lines 213 to 224
/// \brief Finds symbols declared with a static lifetime in the given
/// `root_function` or one of the functions it calls,
/// and adds them to the given `assigns`.
///
/// @param functions all functions of the goto_model
/// @param root_function the root function under which to search statics
/// @param assigns assigns clause where search results are added
///
/// A symbol is considered a static local symbol iff:
/// - it has a static lifetime annotation
/// - its source location has a non-empty function attribute
/// - this function attribute is found in the call graph of the root_function
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \brief Finds symbols declared with a static lifetime in the given
/// `root_function` or one of the functions it calls,
/// and adds them to the given `assigns`.
///
/// @param functions all functions of the goto_model
/// @param root_function the root function under which to search statics
/// @param assigns assigns clause where search results are added
///
/// A symbol is considered a static local symbol iff:
/// - it has a static lifetime annotation
/// - its source location has a non-empty function attribute
/// - this function attribute is found in the call graph of the root_function
/// \brief Finds symbols declared with a static lifetime in the given
/// `root_function` or one of the functions it calls,
/// and adds them to the given `assigns`.
///
/// @param functions All functions of the `goto_model`.
/// @param root_function The root function under which to search statics.
/// @param assigns Assigns clause where search results are added.
///
/// A symbol is considered a static local symbol iff:
/// - it has a static lifetime annotation;
/// - its source location has a non-empty function attribute;
/// - this function attribute is found in the call graph of the `root_function`.

@feliperodri feliperodri changed the title Fix local static variables detection in assigns clause checking instrumentation Fix local static variables detection in assigns clauses Nov 16, 2021
@remi-delmas-3000
Copy link
Collaborator Author

We are now collecting symbols from the symbol table that have a static lifetime and are declare in functions occurring in the call graph of the function under analysis

@@ -0,0 +1,14 @@
CORE
main.c
--enforce-contract bar _ --pointer-primitive-check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there an underscore here (after bar)?

#include <stdlib.h>

static int x;
static int x = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random place for comment: the commit message ...

  1. Could make clear that this is about code contracts;
  2. Should likely have the "A symbol is ..." all moved into the body of the message;
  3. Should likely talk about "called functions" instead of "subfunctions."

@@ -853,18 +856,16 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
function,
symbol_table);

// Adds formal parameters to write set
// fetch local statics of all subfunctions in the symbol_table
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much like the commit message: I don't think "subfunctions" is the right terminology.

Comment on lines 862 to 863
// Full inlining of the function body
goto_function_inline(goto_functions, function, ns, log.get_message_handler());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment could be more useful if it explained why full inlining was necessary. (Also, will this work with recursive functions?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason behind inlining is that in the function f we are instrumenting , a same function g can be called in several locations under different write sets.
Without inlining, for each call site we would have to create a copy of g and instrument for the write set specific to this call site.
Inlining allows us to avoid having to duplicate g and instrument it specifically.

As for inlining recursive functions, I'll implement a check to detect them and error out during inlining

Comment on lines 1286 to 1402
// - this function appears in the call graph of the function
assigns.add_to_write_set(sym.symbol_expr());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about function pointers?

Copy link
Collaborator Author

@remi-delmas-3000 remi-delmas-3000 Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we suppose function pointers have been removed/restricted before this instrumentation phase so that all possible target functions would appear explicitly in the call graph

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we should really include a PRECONDITION in call_graph.cpp's forall_callsites to replace if(function_expr.id()==ID_symbol) by PRECONDITION_WITH_DIAGNOSTICS(function_expr.id() == ID_symbol, "call graph computation requires function pointer removal");.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PRECONDITION added in call_graph.cpp.

Should we also modify goto_function_inline to warn on unresolved function pointers ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should either warn or fail with a PRECONDITION.

Copy link
Contributor

@SaswatPadhi SaswatPadhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments:

@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch from 0531588 to f89fcd4 Compare November 19, 2021 22:18
@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch from f89fcd4 to 09e7bcb Compare November 22, 2021 17:34
@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch 2 times, most recently from b64d75b to 3023ccb Compare November 22, 2021 18:42
Copy link
Contributor

@SaswatPadhi SaswatPadhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

int result = sum(10);
__CPROVER_assert(result == 55, "result == 55");
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] missing newline

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch from 3023ccb to 3dfdd56 Compare November 22, 2021 22:24
@feliperodri
Copy link
Collaborator

@chrisr-diffblue @martin-cs @peterschrammel could you review this PR? It's missing code owner approval.

Copy link
Contributor

@SaswatPadhi SaswatPadhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of minor nitpicks but nothing that would block the merge.

@@ -15,6 +15,8 @@ Date: July 2021

#include <langapi/language_util.h>

#include <analyses/call_graph.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] this should go above langapi include(s).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}
}
}
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant return

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch 2 times, most recently from 455425e to 200246c Compare November 23, 2021 15:01
@remi-delmas-3000 remi-delmas-3000 force-pushed the fix-local-statics-detection branch from 200246c to df40139 Compare November 30, 2021 21:56
…call graph

add INVARIANT for recursive functions and PRECONDITION for function
pointers.

- Static local variables declared in functions called by the function under analysis are now added the write set (same for loops)
- `code_contractst::check_frame_conditions_function` now errors out on recursive functions
- `call_grapht::forall_callsites` now errors out on function pointers
Copy link
Member

@peterschrammel peterschrammel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking, just a few remarks for future work:
That's quite a lot in a single commit. It could have been split into a series of commits:

  • introduce decorator
  • add new tests
  • add static local detection
  • other changes 1
  • other changes 2
  • other changes 3
  • activate/modify tests (separately or with the corresponding commit that makes the test pass)

each of which with a 'why' description in the commit body to make the intent of the PR clearer and easier and faster to review.

@@ -29,6 +29,7 @@ Date: February 2016

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is file is getting way to large. Consider refactoring/splitting in future.

@tautschnig tautschnig merged commit 5750c68 into diffblue:develop Dec 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aws Bugs or features of importance to AWS CBMC users aws-high bugfix Code Contracts Function and loop contracts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants