Skip to content

Make global string_container more resilient to different static init orders #1213

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

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9740142
Handle array initialization with a non-array gracefully
tautschnig Jun 20, 2016
564f64c
added a non-recursive variant of APPLY
Jul 15, 2017
a71ca41
disable linter for assertions
Jul 20, 2017
d078dd8
Support out-of-bounds checks on arrays of dynamic size
tautschnig Jul 20, 2017
6eef691
More complete modelling of fgets
tautschnig Jul 22, 2017
f691135
Import getopt{,_long} and vasprintf models from SV-COMP/busybox
tautschnig Jul 22, 2017
151efbc
Merge pull request #131 from tautschnig/struct-init-error
Aug 3, 2017
eb96b70
increased version number in preparation for release 5.8
Aug 3, 2017
8e70eaa
Merge pull request #1144 from diffblue/miniBDD-non-recursive-apply
Aug 3, 2017
439ef97
fix for operator< on reverse_keyt in miniBDD, fixing segfault in ebmc
Jun 26, 2017
393256f
invariant_violated does not return
Aug 3, 2017
ff945b3
test for miniBDD
Jul 23, 2017
879a47b
Symex support for lhs-typecasts and side effects
tautschnig Jun 26, 2016
08f1a9e
Extract elements of array, struct directly instead of simplifying
tautschnig Jun 26, 2016
f281f88
Removed redundant get_pc() (there is pc())
tautschnig Jun 26, 2016
52db9e4
Fix symex thread statistics
tautschnig Jun 26, 2016
c69a21b
Extended symex progres statistics
tautschnig Jun 26, 2016
acdc797
Symex: output instruction processing and loop unwinding like CBMC
tautschnig Jun 26, 2016
260e03d
symex --max-search-time limit and cleanup
tautschnig Jun 26, 2016
73adfb0
Perform function-pointer removal in symex
tautschnig Apr 19, 2017
e2ed0df
Avoid using integer_typet where unsuitable
tautschnig Jun 19, 2017
0cad6f4
Merge pull request #1062 from diffblue/fix_for_miniBDD
Aug 4, 2017
ea476f7
Merge pull request #151 from tautschnig/symex-improvements
Aug 4, 2017
df81a9c
Merge pull request #1167 from tautschnig/c-library-ext
Aug 4, 2017
bb9cef3
Merge pull request #1035 from tautschnig/no_integer_typet
Aug 4, 2017
a3578c0
Avoid spurious signed/unsigned comparison warnings
tautschnig Aug 4, 2017
652ea09
Merge pull request #1205 from tautschnig/sign-compare-fix
Aug 4, 2017
76ae912
Merge pull request #1158 from tautschnig/array-bounds
Aug 4, 2017
de40333
fix vacuous conjuncts
Aug 4, 2017
548aeba
Stop using C headers
reuk Aug 4, 2017
33811ce
Update coding standard
reuk Aug 4, 2017
2f55076
Enable extractbits over arbitrary types, fix byte extract omission
tautschnig Aug 4, 2017
9d3a99e
Merge pull request #1211 from tautschnig/fix-1209
Aug 4, 2017
4dd5405
Merge pull request #1210 from reuk/stop-using-c-headers
Aug 5, 2017
8314aab
Make string_container static init more resilient
reuk Aug 7, 2017
eb89bc0
Fix up uses of string_container
reuk Aug 7, 2017
39b8cc6
Fix circular initialisation
reuk Aug 7, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CODING_STANDARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ Here a few minimalistic coding rules for the CPROVER source tree.
include in the source file. For example, given `foo.h` and `foo.cpp`, the
line `#include "foo.h"` should precede all other include statements in
`foo.cpp`.
- Use the C++ versions of C headers (e.g. `cmath` instead of `math.h`).
Some of the C headers use macros instead of functions which can have
unexpected consequences.

# Makefiles
- Each source file should appear on a separate line
Expand Down
10 changes: 8 additions & 2 deletions regression/ansi-c/Struct_Initialization1/main.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#define STATIC_ASSERT(condition) \
int some_array##__LINE__[(condition) ? 1 : -1]

struct A {
int x;
int y;
};

struct _classinfo {
char a;
struct A s;
int *interfaces[];
};

struct _classinfo nullclass1 = { 42, 0, 0 };
struct _classinfo nullclass2 = { 42, { 0, 0 } };
struct _classinfo nullclass1 = { 42, 1, 2, 3, 4 };
struct _classinfo nullclass2 = { 42, { 1, 2 }, { 3, 4 } };

STATIC_ASSERT(sizeof(nullclass1)==sizeof(struct _classinfo));
STATIC_ASSERT(sizeof(nullclass2)==sizeof(struct _classinfo));
Expand Down
2 changes: 1 addition & 1 deletion regression/ansi-c/Struct_Initialization1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.c

^EXIT=0$
Expand Down
24 changes: 24 additions & 0 deletions regression/ansi-c/Struct_Initialization2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#define STATIC_ASSERT(condition) \
int some_array##__LINE__[(condition) ? 1 : -1]

struct A {
int x;
int y;
int arr[];
};

struct _classinfo {
char a;
struct A s;
int *interfaces[];
};

struct _classinfo nullclass1 = { 42, 1, 2, 0, 3, 4 };
struct _classinfo nullclass2 = { 42, { 1, 2, 0 }, { 3, 4 } };

STATIC_ASSERT(sizeof(nullclass1)==sizeof(struct _classinfo));
STATIC_ASSERT(sizeof(nullclass2)==sizeof(struct _classinfo));

int main()
{
}
10 changes: 10 additions & 0 deletions regression/ansi-c/Struct_Initialization2/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c

^EXIT=(64|1)$
^SIGNAL=0$
^CONVERSION ERROR$
--
^warning: ignoring
--
variable-length arrays in the middle of a struct are not permitted
14 changes: 14 additions & 0 deletions regression/cbmc/dynamic_size1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <stdlib.h>

int main()
{
unsigned x;

int *A=malloc(x*sizeof(int));

char *p=&A[1];

char c=*p;

return c;
}
9 changes: 9 additions & 0 deletions regression/cbmc/dynamic_size1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c
--pointer-check
^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
--
^warning: ignoring
^unknown or invalid type size:
22 changes: 22 additions & 0 deletions regression/cbmc/fgets1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <stdio.h>
#include <assert.h>

int main()
{
char buffer[3]={'a', 'b', '\0'};
FILE *f=fdopen(0, "r");
if(!f)
return 1;

char *p=fgets(buffer, 3, f);
if(p)
{
assert(buffer[1]==p[1]);
assert(buffer[2]=='\0');
assert(p[1]=='b'); // expected to fail
}

fclose(f);

return 0;
}
10 changes: 10 additions & 0 deletions regression/cbmc/fgets1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--bounds-check --pointer-check
^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
\[main.assertion.3\] assertion p\[1\]=='b': FAILURE
\*\* 1 of 38 failed \(2 iterations\)
--
^warning: ignoring
35 changes: 35 additions & 0 deletions regression/cbmc/union9/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <stdlib.h>
#include <stdint.h>

typedef union {
struct {
uint8_t x;
uint8_t z;
} b;
} union_t;

typedef struct {
uint32_t magic;
union_t unions[];
} flex;

int flex_init(flex * flex, size_t num)
{
if (num == 0 || num >= 200) {
return -1;
}
flex->unions[num - 1].b.z = 255;
return 0;
}

int main() {
uint8_t num = nondet_size();
flex * pool = (flex *) malloc(sizeof(flex) + num * sizeof(union_t));
int ret = flex_init(pool, num);
if (num > 0 && num < 200) {
__CPROVER_assert(ret == 0, "Accept inside range");
} else {
__CPROVER_assert(ret != 0, "Reject outside range");
}
}

8 changes: 8 additions & 0 deletions regression/cbmc/union9/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c

^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
^warning: ignoring
5 changes: 3 additions & 2 deletions src/ansi-c/c_typecheck_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ class c_typecheck_baset:
const typet &type,
bool force_constant);

virtual void do_designated_initializer(
virtual exprt::operandst::const_iterator do_designated_initializer(
exprt &result,
designatort &designator,
const exprt &value,
const exprt &initializer_list,
exprt::operandst::const_iterator init_it,
bool force_constant);

designatort make_designator(const typet &type, const exprt &src);
Expand Down
77 changes: 56 additions & 21 deletions src/ansi-c/c_typecheck_initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ void c_typecheck_baset::designator_enter(
const typet &type,
designatort &designator)
{
designatort::entryt entry;
entry.type=type;
entry.index=0;
designatort::entryt entry(type);

const typet &full_type=follow(type);

Expand All @@ -268,6 +266,8 @@ void c_typecheck_baset::designator_enter(

entry.size=struct_type.components().size();
entry.subtype.make_nil();
// only a top-level struct may end with a variable-length array
entry.vla_permitted=designator.empty();

for(struct_typet::componentst::const_iterator
it=struct_type.components().begin();
Expand Down Expand Up @@ -351,12 +351,16 @@ void c_typecheck_baset::designator_enter(

/// \param pre:initialized result, designator
/// \return sets result
void c_typecheck_baset::do_designated_initializer(
exprt::operandst::const_iterator c_typecheck_baset::do_designated_initializer(
exprt &result,
designatort &designator,
const exprt &value,
const exprt &initializer_list,
exprt::operandst::const_iterator init_it,
bool force_constant)
{
// copy the value, we may need to adjust it
exprt value=*init_it;

assert(!designator.empty());

if(value.id()==ID_designated_initializer)
Expand All @@ -370,8 +374,10 @@ void c_typecheck_baset::do_designated_initializer(

assert(!designator.empty());

return do_designated_initializer(
result, designator, value.op0(), force_constant);
// discard the return value
do_designated_initializer(
result, designator, value, value.operands().begin(), force_constant);
return ++init_it;
}

exprt *dest=&result;
Expand Down Expand Up @@ -503,7 +509,7 @@ void c_typecheck_baset::do_designated_initializer(

assert(full_type==follow(dest->type()));

return; // done
return ++init_it; // done
}

// union? The component in the zero initializer might
Expand Down Expand Up @@ -537,7 +543,7 @@ void c_typecheck_baset::do_designated_initializer(
if(value.id()==ID_initializer_list)
{
*dest=do_initializer_rec(value, type, force_constant);
return; // done
return ++init_it; // done
}
else if(value.id()==ID_string_constant)
{
Expand All @@ -549,7 +555,7 @@ void c_typecheck_baset::do_designated_initializer(
follow(full_type.subtype()).id()==ID_unsignedbv))
{
*dest=do_initializer_rec(value, type, force_constant);
return; // done
return ++init_it; // done
}
}
else if(follow(value.type())==full_type)
Expand All @@ -562,7 +568,7 @@ void c_typecheck_baset::do_designated_initializer(
full_type.id()==ID_vector)
{
*dest=value;
return; // done
return ++init_it; // done
}
}

Expand All @@ -574,21 +580,49 @@ void c_typecheck_baset::do_designated_initializer(
// we are initializing a compound type, and enter it!
// this may change the type, full_type might not be valid any more
const typet dest_type=full_type;
const bool vla_permitted=designator.back().vla_permitted;
designator_enter(type, designator);

// GCC permits (though issuing a warning with -Wall) composite
// types built from flat initializer lists
if(dest->operands().empty())
{
err_location(value);
error() << "cannot initialize type `"
<< to_string(dest_type) << "' using value `"
<< to_string(value) << "'" << eom;
throw 0;
warning().source_location=value.find_source_location();
warning() << "initialisation of " << full_type.id()
<< " requires initializer list, found "
<< value.id() << " instead" << eom;

// in case of a variable-length array consume all remaining
// initializer elements
if(vla_permitted &&
dest_type.id()==ID_array &&
(to_array_type(dest_type).size().is_zero() ||
to_array_type(dest_type).size().is_nil()))
{
value.id(ID_initializer_list);
value.operands().clear();
for( ; init_it!=initializer_list.operands().end(); ++init_it)
value.copy_to_operands(*init_it);
*dest=do_initializer_rec(value, dest_type, force_constant);

return init_it;
}
else
{
err_location(value);
error() << "cannot initialize type `"
<< to_string(dest_type) << "' using value `"
<< to_string(value) << "'" << eom;
throw 0;
}
}

dest=&(dest->op0());

// we run into another loop iteration
}

return ++init_it;
}

void c_typecheck_baset::increment_designator(designatort &designator)
Expand Down Expand Up @@ -651,8 +685,7 @@ designatort c_typecheck_baset::make_designator(
forall_operands(it, src)
{
const exprt &d_op=*it;
designatort::entryt entry;
entry.type=type;
designatort::entryt entry(type);
const typet &full_type=follow(entry.type);

if(full_type.id()==ID_array)
Expand Down Expand Up @@ -856,10 +889,12 @@ exprt c_typecheck_baset::do_initializer_list(

designator_enter(type, current_designator);

forall_operands(it, value)
const exprt::operandst &operands=value.operands();
for(exprt::operandst::const_iterator it=operands.begin();
it!=operands.end(); ) // no ++it
{
do_designated_initializer(
result, current_designator, *it, force_constant);
it=do_designated_initializer(
result, current_designator, value, it, force_constant);

// increase designator -- might go up
increment_designator(current_designator);
Expand Down
4 changes: 3 additions & 1 deletion src/ansi-c/designator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ class designatort
{
size_t index;
size_t size;
bool vla_permitted;
typet type, subtype;

entryt():index(0), size(0)
explicit entryt(const typet &type):
index(0), size(0), vla_permitted(false), type(type)
{
}
};
Expand Down
Loading