Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

int main()
{
int *q = malloc(10);
int *r = malloc(10);

int *p = r;
if(nondet())
p = q;
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(heap-allocation-0\[0\]\), ptr ->\(heap-allocation-1\[0\]\) :value-set-end
--
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

int main()
{
int *p = malloc(10);
if(nondet())
++p;
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-2/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(heap-allocation-0\[0\]\), ptr ->\(heap-allocation-0\[1\]\) :value-set-end
--
10 changes: 10 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-3/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

int main()
{
int *q = malloc(10);
int r[10];

int *p = r;
if(nondet())
p = q;
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-3/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(main::1::r\[0\]\), ptr ->\(heap-allocation-0\[0\]\) :value-set-end
--
10 changes: 10 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-4/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

int main()
{
int *q = malloc(10);
int r[10];

int *p = q;
if(nondet())
p = r;
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-4/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(main::1::r\[0\]\), ptr ->\(heap-allocation-0\[0\]\) :value-set-end
--
8 changes: 8 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-5/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

int main()
{
int *p = malloc(10);

if(non_det())
p = malloc(20);
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-5/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(heap-allocation-0\[0\]\), ptr ->\(heap-allocation-1\[0\]\) :value-set-end
--
5 changes: 5 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-6/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

int main()
{
int *p = nondet() ? malloc(10) : malloc(20);
}
7 changes: 7 additions & 0 deletions regression/goto-analyzer/heap-allocation-nondet-6/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(heap-allocation-0\[0\]\), ptr ->\(heap-allocation-1\[0\]\) :value-set-end
--
20 changes: 20 additions & 0 deletions regression/goto-analyzer/heap-allocation-write-2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

int main()
{
int *p = malloc(sizeof(int) * 5);
int *q = malloc(sizeof(int) * 10);

int *pp = p;

*p = 10;
++p;
*p = 20;

q[0] = 100;
q[99] = 101;

assert(pp[0] == 10);
assert(pp[1] == 20);
assert(q[0] == 100);
assert(q[99] == 101);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers constants --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*p\[.*0\] == 10: SUCCESS
\[main.assertion.2\] .*p\[.*1\] == 20: SUCCESS
\[main.assertion.3\] .*q\[.*0\] == 100: SUCCESS
\[main.assertion.4\] .*q\[.*99\] == 101: SUCCESS
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers top-bottom --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*p\[.*0\] == 10: UNKNOWN
\[main.assertion.2\] .*p\[.*1\] == 20: UNKNOWN
\[main.assertion.3\] .*q\[.*0\] == 100: UNKNOWN
\[main.assertion.4\] .*q\[.*99\] == 101: UNKNOWN
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*p\[.*0\] == 10: SUCCESS
\[main.assertion.2\] .*p\[.*1\] == 20: SUCCESS
\[main.assertion.3\] .*q\[.*0\] == 100: SUCCESS
\[main.assertion.4\] .*q\[.*99\] == 101: SUCCESS
--
18 changes: 18 additions & 0 deletions regression/goto-analyzer/heap-allocation-write/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

int main()
{
int *i_was_malloced = malloc(sizeof(int) * 10);
int *alias = i_was_malloced;

*i_was_malloced = 99;
assert(*alias == 99);

i_was_malloced[0] = 100;
assert(*alias == 100);

*alias += 1;
assert(i_was_malloced[0] == 101);

i_was_malloced[1] = 102;
assert(alias[1] == 102);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers constants --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*alias == 99: SUCCESS
\[main.assertion.2\] .*alias == 100: SUCCESS
\[main.assertion.3\] .*i_was_malloced\[.*0\] == 101: SUCCESS
\[main.assertion.4\] .*alias\[.*1\] == 102: SUCCESS
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers top-bottom --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*alias == 99: UNKNOWN
\[main.assertion.2\] .*alias == 100: UNKNOWN
\[main.assertion.3\] .*i_was_malloced\[.*0\] == 101: UNKNOWN
\[main.assertion.4\] .*alias\[.*1\] == 102: UNKNOWN
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --vsd-arrays every-element --verify
^EXIT=0$
^SIGNAL=0$
\[main.assertion.1\] .*alias == 99: SUCCESS
\[main.assertion.2\] .*alias == 100: SUCCESS
\[main.assertion.3\] .*i_was_malloced\[.*0\] == 101: SUCCESS
\[main.assertion.4\] .*alias\[.*1\] == 102: SUCCESS
--
6 changes: 6 additions & 0 deletions regression/goto-analyzer/heap-allocation/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

int main()
{
int *p = malloc(sizeof(int) * 10);
int *q = malloc(sizeof(int) * 5);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c
--variable-sensitivity --vsd-pointers constants --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> ptr ->\(heap-allocation-0\[0\]\)
main::1::q \(\) -> ptr ->\(heap-allocation-1\[0\]\)
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c
--variable-sensitivity --vsd-pointers top-bottom --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> TOP
main::1::q \(\) -> TOP
--
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c
--variable-sensitivity --vsd-pointers value-set --show
^EXIT=0$
^SIGNAL=0$
main::1::p \(\) -> value-set-begin: ptr ->\(heap-allocation-0\[0\]\) :value-set-end
main::1::q \(\) -> value-set-begin: ptr ->\(heap-allocation-1\[0\]\) :value-set-end
--
10 changes: 10 additions & 0 deletions src/analyses/variable-sensitivity/abstract_environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ abstract_environmentt::eval(const exprt &expr, const namespacet &ns) const
return abstract_object_factory(simplified_expr.type(), simplified_expr, ns);
}

if(
simplified_id == ID_side_effect &&
(simplified_expr.get(ID_statement) == ID_allocate))
{
return abstract_object_factory(
typet(ID_dynamic_object),
exprt(ID_dynamic_object, simplified_expr.type()),
ns);
}

// No special handling required by the abstract environment
// delegate to the abstract object
if(!simplified_expr.operands().empty())
Expand Down
23 changes: 23 additions & 0 deletions src/analyses/variable-sensitivity/abstract_pointer_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ abstract_object_pointert abstract_pointer_objectt::expression_transform(
if(expr.id() == ID_dereference)
return read_dereference(environment, ns);

if(expr.id() == ID_typecast)
{
const typecast_exprt &tce = to_typecast_expr(expr);
if(tce.op().id() == ID_symbol && is_void_pointer(tce.op().type()))
{
auto obj = environment.eval(tce.op(), ns);
auto pointer = std::dynamic_pointer_cast<const abstract_pointer_objectt>(
obj->unwrap_context());
if(pointer)
return pointer->typecast(tce.type(), environment, ns);
}
}

return abstract_objectt::expression_transform(
expr, operands, environment, ns);
}
Expand Down Expand Up @@ -87,6 +100,16 @@ abstract_object_pointert abstract_pointer_objectt::write_dereference(
return std::make_shared<abstract_pointer_objectt>(type(), true, false);
}

abstract_object_pointert abstract_pointer_objectt::typecast(
const typet &new_type,
const abstract_environmentt &environment,
const namespacet &ns) const
{
INVARIANT(is_void_pointer(type()), "Only allow pointer casting from void*");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I feel kind of conflicted about this. In some ways it should not be an INVARIANT because it can be triggered by a user but also, at the moment we really aren't handling this case. Could we return a TOP pointer of the correct type? Reads from that should give TOP and writes to it could call havoc()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am similarly conflicted. Right now, the call to typecast() is itself guarded so that it will never be called if this invariant will fire

  if(expr.id() == ID_typecast)
  {
    const typecast_exprt &tce = to_typecast_expr(expr);
    if(tce.op().id() == ID_symbol && is_void_pointer(tce.op().type()))

Consequently existing typecasts, of which there are a handful, will evaluate as they do at the moment. I suppose this invariant is more of warning for future care than a guard against wacky corner cases.

return std::make_shared<abstract_pointer_objectt>(
new_type, is_top(), is_bottom());
}

void abstract_pointer_objectt::get_statistics(
abstract_object_statisticst &statistics,
abstract_object_visitedt &visited,
Expand Down
5 changes: 5 additions & 0 deletions src/analyses/variable-sensitivity/abstract_pointer_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ class abstract_pointer_objectt : public abstract_objectt,
const std::stack<exprt> &stack,
const abstract_object_pointert &value,
bool merging_write) const;

virtual abstract_object_pointert typecast(
const typet &new_type,
const abstract_environmentt &environment,
const namespacet &ns) const;
};

#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_POINTER_OBJECT_H
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "constant_pointer_abstract_object.h"

#include <analyses/variable-sensitivity/abstract_environment.h>
#include <util/arith_tools.h>
#include <util/c_types.h>
#include <util/pointer_expr.h>
#include <util/std_expr.h>

Expand All @@ -33,8 +35,10 @@ constant_pointer_abstract_objectt::constant_pointer_abstract_objectt(
}

constant_pointer_abstract_objectt::constant_pointer_abstract_objectt(
const typet &new_type,
const constant_pointer_abstract_objectt &old)
: abstract_pointer_objectt(old), value_stack(old.value_stack)
: abstract_pointer_objectt(new_type, old.is_top(), old.is_bottom()),
value_stack(old.value_stack)
{
}

Expand Down Expand Up @@ -121,6 +125,10 @@ void constant_pointer_abstract_objectt::output(

out << symbol_pointed_to.get_identifier();
}
else if(addressee.id() == ID_dynamic_object)
{
out << addressee.get(ID_identifier);
}
else if(addressee.id() == ID_index)
{
auto const &array_index = to_index_expr(addressee);
Expand Down Expand Up @@ -201,14 +209,41 @@ abstract_object_pointert constant_pointer_abstract_objectt::write_dereference(
abstract_object_pointert modified_value =
environment.write(pointed_value, new_value, stack, ns, merging_write);
environment.assign(value, modified_value, ns);

// but the pointer itself does not change!
}
return std::dynamic_pointer_cast<const constant_pointer_abstract_objectt>(
shared_from_this());

return shared_from_this();
}
}

abstract_object_pointert constant_pointer_abstract_objectt::typecast(
const typet &new_type,
const abstract_environmentt &environment,
const namespacet &ns) const
{
INVARIANT(is_void_pointer(type()), "Only allow pointer casting from void*");
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above.


// Get an expression that we can assign to
exprt value = to_address_of_expr(value_stack.to_expression()).object();
if(value.id() == ID_dynamic_object)
{
auto &env = const_cast<abstract_environmentt &>(environment);

auto heap_array_type = array_typet(new_type.subtype(), nil_exprt());
auto array_object =
environment.abstract_object_factory(heap_array_type, ns, true, false);
auto heap_symbol = symbol_exprt(value.get(ID_identifier), heap_array_type);
env.assign(heap_symbol, array_object, ns);
auto heap_address = address_of_exprt(
index_exprt(heap_symbol, from_integer(0, signed_size_type())));
auto new_pointer = std::make_shared<constant_pointer_abstract_objectt>(
heap_address, env, ns);
return new_pointer;
}

return std::make_shared<constant_pointer_abstract_objectt>(new_type, *this);
}

void constant_pointer_abstract_objectt::get_statistics(
abstract_object_statisticst &statistics,
abstract_object_visitedt &visited,
Expand Down
Loading