Skip to content

Commit ff47643

Browse files
Add support for nondet initialisation of dynamic C strings
1 parent 25be369 commit ff47643

File tree

6 files changed

+151
-11
lines changed

6 files changed

+151
-11
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
#include <stddef.h>
3+
#include <string.h>
4+
5+
int test(char *string, size_t size)
6+
{
7+
for(size_t ix = 0; ix + 1 < size; ++ix)
8+
{
9+
char c = string[ix];
10+
// characters except the last should fall in printable range
11+
assert(c == '\n' | c == '\r' | c == '\t' | (c >= 32 && c <= 126));
12+
}
13+
assert(strlen(string) + 1 == size);
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
test.c
3+
--function test --pointers-to-treat-as-string string --associated-array-sizes string:size --pointer-check --unwind 10
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--

src/ansi-c/ansi_c_language.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Author: Daniel Kroening, [email protected]
2626
"(pointers-to-treat-as-array):" \
2727
"(associated-array-sizes):" \
2828
"(max-dynamic-array-size):" \
29+
"(pointers-to-treat-as-string):"
2930

3031
#define HELP_ANSI_C_LANGUAGE \
3132
" --max-nondet-tree-depth N limit size of nondet (e.g. input) object tree;\n" /* NOLINT(*) */\

src/ansi-c/c_nondet_symbol_factory.cpp

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ class symbol_factoryt
8484
std::size_t depth,
8585
const recursion_sett &recursion_set);
8686

87+
void gen_nondet_string_member_initialization(
88+
code_blockt &assignments,
89+
const exprt &array,
90+
const exprt &array_size,
91+
std::size_t depth,
92+
const recursion_sett &recursion_set);
93+
8794
private:
8895
/// Add a new variable symbol to the symbol table
8996
/// \param type: The type of the new variable
@@ -216,14 +223,29 @@ void symbol_factoryt::gen_nondet_init(
216223
using std::placeholders::_5;
217224
if(object_factory_params.should_be_treated_as_array(symbol_name))
218225
{
219-
gen_array_initialization_t gen_array_initialization = std::bind(
220-
&symbol_factoryt::gen_nondet_array_member_initialization,
221-
this,
222-
_1,
223-
_2,
224-
_3,
225-
_4,
226-
_5);
226+
gen_array_initialization_t gen_array_initialization;
227+
if(object_factory_params.should_be_treated_as_string(symbol_name))
228+
{
229+
gen_array_initialization = std::bind(
230+
&symbol_factoryt::gen_nondet_string_member_initialization,
231+
this,
232+
_1,
233+
_2,
234+
_3,
235+
_4,
236+
_5);
237+
}
238+
else
239+
{
240+
gen_array_initialization = std::bind(
241+
&symbol_factoryt::gen_nondet_array_member_initialization,
242+
this,
243+
_1,
244+
_2,
245+
_3,
246+
_4,
247+
_5);
248+
}
227249
gen_nondet_size_array_init(
228250
assignments,
229251
symbol_expr,
@@ -524,6 +546,76 @@ void symbol_factoryt::gen_nondet_array_member_initialization(
524546
assignments.add(std::move(array_member_init));
525547
}
526548

549+
void symbol_factoryt::gen_nondet_string_member_initialization(
550+
code_blockt &assignments,
551+
const exprt &array,
552+
const exprt &array_size,
553+
std::size_t depth,
554+
const symbol_factoryt::recursion_sett &recursion_set)
555+
{
556+
// for(size_t ix = 0; ix + 1 < array_size; ++ix) {
557+
// assume(arr[ix] == '\n'
558+
// || arr[ix] == '\t'
559+
// || arr[ix] == '\r'
560+
// || (32 <= arr[ix] && arr[ix] <= 126));
561+
// }
562+
563+
auto const &array_index_symbol =
564+
new_tmp_symbol(size_type(), CPROVER_PREFIX "array_index");
565+
auto array_member_init = code_fort{};
566+
567+
array_member_init.init() = code_assignt{array_index_symbol.symbol_expr(),
568+
from_integer(0, size_type())};
569+
570+
array_member_init.cond() = binary_exprt{
571+
plus_exprt{array_index_symbol.symbol_expr(), from_integer(1, size_type())},
572+
ID_lt,
573+
array_size,
574+
bool_typet{}};
575+
576+
auto const array_member = dereference_exprt{
577+
plus_exprt{array, array_index_symbol.symbol_expr(), array.type()}};
578+
579+
auto array_member_init_body = code_blockt{};
580+
array_member_init_body.add(code_assumet{typecast_exprt{
581+
bitor_exprt{
582+
typecast_exprt{equal_exprt{array_member, from_integer('\n', char_type())},
583+
signed_int_type()},
584+
bitor_exprt{
585+
typecast_exprt{
586+
equal_exprt{array_member, from_integer('\t', char_type())},
587+
signed_int_type()},
588+
bitor_exprt{
589+
typecast_exprt{
590+
equal_exprt{array_member, from_integer('\r', char_type())},
591+
signed_int_type()},
592+
bitand_exprt{typecast_exprt{
593+
binary_relation_exprt{
594+
from_integer(32, char_type()), ID_le, array_member},
595+
signed_int_type()},
596+
typecast_exprt{
597+
binary_relation_exprt{
598+
array_member, ID_le, from_integer(126, char_type())},
599+
signed_int_type()}},
600+
}}},
601+
bool_typet{}}});
602+
array_member_init_body.add(
603+
code_assignt{array_index_symbol.symbol_expr(),
604+
plus_exprt{array_index_symbol.symbol_expr(),
605+
from_integer(1, size_type()),
606+
size_type()}});
607+
array_member_init.body() = std::move(array_member_init_body);
608+
assignments.add(std::move(array_member_init));
609+
610+
// array[array_size - 1] = '\0';
611+
assignments.add(
612+
code_assignt{dereference_exprt{plus_exprt{
613+
array,
614+
minus_exprt{array_size, from_integer(1, size_type())},
615+
array.type()}},
616+
from_integer(0, char_type())});
617+
}
618+
527619
const symbolt &
528620
symbol_factoryt::gen_malloc_function(const irep_idt &malloc_symbol_name)
529621
{

src/ansi-c/c_object_factory_parameters.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ void parse_c_object_factory_options(const cmdlinet &cmdline, optionst &options)
2525
"pointers-to-treat-as-array",
2626
cmdline.get_comma_separated_values("pointers-to-treat-as-array"));
2727
}
28+
if(cmdline.isset("pointers-to-treat-as-string"))
29+
{
30+
options.set_option(
31+
"pointers-to-treat-as-string",
32+
cmdline.get_comma_separated_values("pointers-to-treat-as-string"));
33+
}
2834
if(cmdline.isset("associated-array-sizes"))
2935
{
3036
options.set_option(
@@ -38,6 +44,13 @@ void parse_c_object_factory_options(const cmdlinet &cmdline, optionst &options)
3844
}
3945
}
4046

47+
bool c_object_factory_parameterst::should_be_treated_as_array(irep_idt id) const
48+
{
49+
return pointers_to_treat_as_array.find(id) !=
50+
pointers_to_treat_as_array.end() ||
51+
should_be_treated_as_string(id);
52+
}
53+
4154
void c_object_factory_parameterst::set(const optionst &options)
4255
{
4356
object_factory_parameterst::set(options);
@@ -50,6 +63,16 @@ void c_object_factory_parameterst::set(const optionst &options)
5063
this->pointers_to_treat_as_array, this->pointers_to_treat_as_array.end()),
5164
id2string);
5265

66+
auto const &pointers_to_treat_as_string =
67+
options.get_list_option("pointers-to-treat-as-string");
68+
std::transform(
69+
std::begin(pointers_to_treat_as_string),
70+
std::end(pointers_to_treat_as_string),
71+
std::inserter(
72+
this->pointers_to_treat_as_string,
73+
this->pointers_to_treat_as_string.end()),
74+
id2string);
75+
5376
if(options.is_set("max-dynamic-array-size"))
5477
{
5578
max_dynamic_array_size =
@@ -117,8 +140,9 @@ optionalt<irep_idt> c_object_factory_parameterst::get_associated_size_variable(
117140
array_name_to_associated_array_size_variable, array_id);
118141
}
119142

120-
bool c_object_factory_parameterst::should_be_treated_as_array(irep_idt id) const
143+
bool c_object_factory_parameterst::should_be_treated_as_string(
144+
irep_idt id) const
121145
{
122-
return pointers_to_treat_as_array.find(id) !=
123-
pointers_to_treat_as_array.end();
146+
return pointers_to_treat_as_string.find(id) !=
147+
pointers_to_treat_as_string.end();
124148
}

src/ansi-c/c_object_factory_parameters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct c_object_factory_parameterst final : public object_factory_parameterst
2727
}
2828

2929
bool should_be_treated_as_array(irep_idt id) const;
30+
bool should_be_treated_as_string(irep_idt id) const;
3031
bool is_array_size_parameter(irep_idt id) const;
3132
optionalt<irep_idt> get_associated_size_variable(irep_idt array_id) const;
3233

@@ -38,6 +39,7 @@ struct c_object_factory_parameterst final : public object_factory_parameterst
3839
std::set<irep_idt> pointers_to_treat_as_array;
3940
std::set<irep_idt> variables_that_hold_array_sizes;
4041
std::map<irep_idt, irep_idt> array_name_to_associated_array_size_variable;
42+
std::set<irep_idt> pointers_to_treat_as_string;
4143
};
4244

4345
/// Parse the c object factory parameters from a given command line

0 commit comments

Comments
 (0)