Skip to content

Commit 1b03a35

Browse files
author
Remi Delmas
committed
Fixes local static variables detection. A symbol is detected as a local static
if it is static and declared in one of the subfunctions of the function under analysis.
1 parent e27dba6 commit 1b03a35

File tree

5 files changed

+108
-14
lines changed

5 files changed

+108
-14
lines changed

regression/contracts/assigns_enforce_statics/main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#include <assert.h>
22
#include <stdlib.h>
33

4-
static int x;
4+
static int x = 0;
55

66
void foo() __CPROVER_assigns(x)
77
{
88
int *y = &x;
99

10-
static int x;
10+
static int x = 0;
11+
12+
// should pass (assigns local x)
1113
x++;
1214

15+
// should fail (assigns global x)
1316
(*y)++;
1417
}
1518

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
static int x;
5+
static int xx;
6+
7+
void foo()
8+
{
9+
int *y = &x;
10+
int *yy = &xx;
11+
12+
static int x;
13+
// must pass (modifies local static)
14+
x++;
15+
16+
// must pass (modifies assignable global static )
17+
(*y)++;
18+
19+
// must fail (modifies non-assignable global static)
20+
(*yy)++;
21+
}
22+
23+
void bar() __CPROVER_assigns(x)
24+
{
25+
foo();
26+
}
27+
28+
int main()
29+
{
30+
bar();
31+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--enforce-contract bar _ --pointer-primitive-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[foo.\d+\] line \d+ Check that y is assignable: SUCCESS$
7+
^\[foo.\d+\] line \d+ Check that foo\$\$1\$\$x is assignable: SUCCESS$
8+
^\[foo.\d+\] line \d+ Check that \*y is assignable: SUCCESS$
9+
^\[foo.\d+\] line \d+ Check that \*yy is assignable: FAILURE$
10+
^VERIFICATION FAILED$
11+
--
12+
--
13+
Checks whether static local and global variables are correctly tracked
14+
in assigns clause verification, accross subfunction calls.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ Date: February 2016
1515

1616
#include <algorithm>
1717
#include <map>
18+
#include <util/find_symbols.h>
19+
#include <util/std_code.h>
1820

21+
#include <analyses/call_graph.h>
1922
#include <analyses/local_may_alias.h>
2023

2124
#include <ansi-c/c_expr.h>
@@ -853,18 +856,16 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
853856
function,
854857
symbol_table);
855858

856-
// Adds formal parameters to write set
859+
// fetch local statics of all subfunctions in the symbol_table
860+
find_static_locals(goto_functions, function, assigns);
861+
862+
// Full inlining of the function body
863+
goto_function_inline(goto_functions, function, ns, log.get_message_handler());
864+
865+
// Add formal parameters to write set
857866
for(const auto &param : to_code_type(target.type).parameters())
858867
assigns.add_to_write_set(ns.lookup(param.get_identifier()).symbol_expr());
859868

860-
// Adds local static declarations to write set
861-
for(const auto &sym_pair : symbol_table)
862-
{
863-
const auto &sym = sym_pair.second;
864-
if(sym.is_static_lifetime && sym.location.get_function() == function)
865-
assigns.add_to_write_set(sym.symbol_expr());
866-
}
867-
868869
auto instruction_it = function_obj->second.body.instructions.begin();
869870
for(const auto &car : assigns.get_write_set())
870871
{
@@ -886,8 +887,6 @@ void code_contractst::check_frame_conditions(
886887
goto_programt::targett &instruction_it,
887888
assigns_clauset &assigns)
888889
{
889-
goto_function_inline(goto_functions, function, ns, log.get_message_handler());
890-
891890
for(; instruction_it != body.instructions.end(); ++instruction_it)
892891
{
893892
if(instruction_it->is_decl())
@@ -1260,3 +1259,34 @@ bool code_contractst::enforce_contracts(const std::set<std::string> &to_enforce)
12601259
}
12611260
return fail;
12621261
}
1262+
1263+
void code_contractst::find_static_locals(
1264+
const goto_functionst &functions,
1265+
const irep_idt &root_function,
1266+
assigns_clauset &assigns)
1267+
{
1268+
auto cg =
1269+
call_grapht::create_from_root_function(functions, root_function, true);
1270+
auto g = cg.get_directed_graph();
1271+
1272+
// Adds local static declarations to write set
1273+
for(const auto &sym_pair : symbol_table)
1274+
{
1275+
const auto &sym = sym_pair.second;
1276+
if(sym.is_static_lifetime)
1277+
{
1278+
auto fname = sym.location.get_function();
1279+
if(
1280+
!fname.empty() &&
1281+
(fname == root_function || g.get_node_index(fname).has_value()))
1282+
{
1283+
// the symbol has
1284+
// - a static lifetime
1285+
// - non empty location function
1286+
// - this function appears in the call graph of the function
1287+
assigns.add_to_write_set(sym.symbol_expr());
1288+
}
1289+
}
1290+
}
1291+
return;
1292+
}

src/goto-instrument/contracts/contracts.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ class code_contractst
5858
goto_functions(goto_model.goto_functions),
5959
log(log),
6060
converter(symbol_table, log.get_message_handler())
61-
6261
{
6362
}
6463

@@ -210,6 +209,23 @@ class code_contractst
210209
codet &expression,
211210
source_locationt location,
212211
const irep_idt &mode);
212+
213+
/// \brief Finds symbols declared with a static lifetime in the given
214+
/// `root_function` or one of the functions it calls,
215+
/// and adds them to the given `assigns`.
216+
///
217+
/// @param functions all functions of the goto_model
218+
/// @param root_function the root function under which to search statics
219+
/// @param assigns assigns clause where search results are added
220+
///
221+
/// A symbol is considered a static local symbol iff:
222+
/// - it has a static lifetime annotation
223+
/// - its source location has a non-empty function attribute
224+
/// - this function attribute is found in the call graph of the root_function
225+
void find_static_locals(
226+
const goto_functionst &functions,
227+
const irep_idt &root_function,
228+
assigns_clauset &assigns);
213229
};
214230

215231
#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_CONTRACTS_H

0 commit comments

Comments
 (0)