Skip to content

Commit

Permalink
Merge pull request #1834 from diffblue/library-preconditions
Browse files Browse the repository at this point in the history
Library preconditions
  • Loading branch information
tautschnig authored Feb 14, 2018
2 parents ef08ae2 + f6f45fc commit 7b5dd17
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 122 deletions.
2 changes: 1 addition & 1 deletion regression/cbmc/strcat1/test.desc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ main.c
^SIGNAL=0$
^VERIFICATION FAILED$
\[main.assertion.6\] assertion strlen\(A3\) == 4: FAILURE
\*\* 1 of 8 failed
\*\* 1 of 9 failed
--
^warning: ignoring
17 changes: 10 additions & 7 deletions src/ansi-c/library/inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ in_addr_t __VERIFIER_nondet_in_addr_t();
in_addr_t inet_addr(const char *cp)
{
__CPROVER_HIDE:;
(void)*cp;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_addr zero-termination of argument");
__CPROVER_precondition(__CPROVER_is_zero_string(cp),
"inet_addr zero-termination of argument");
#endif
(void)*cp;

in_addr_t result=__VERIFIER_nondet_in_addr_t();
return result;
Expand All @@ -37,11 +38,12 @@ int __VERIFIER_nondet_int();
int inet_aton(const char *cp, struct in_addr *pin)
{
__CPROVER_HIDE:;
(void)*cp;
(void)*pin;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_aton zero-termination of name argument");
__CPROVER_precondition(__CPROVER_is_zero_string(cp),
"inet_aton zero-termination of name argument");
#endif
(void)*cp;
(void)*pin;

int result=__VERIFIER_nondet_int();
return result;
Expand All @@ -63,10 +65,11 @@ in_addr_t __VERIFIER_nondet_in_addr_t();
in_addr_t inet_network(const char *cp)
{
__CPROVER_HIDE:;
(void)*cp;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_network zero-termination of name argument");
__CPROVER_precondition(__CPROVER_is_zero_string(cp),
"inet_network zero-termination of name argument");
#endif
(void)*cp;

in_addr_t result=__VERIFIER_nondet_in_addr_t();
return result;
Expand Down
5 changes: 3 additions & 2 deletions src/ansi-c/library/netdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ __CPROVER_bool __VERIFIER_nondet___CPROVER_bool();
struct hostent *gethostbyname(const char *name)
{
__CPROVER_HIDE:;
(void)*name;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(name), "gethostbyname zero-termination of name argument");
__CPROVER_precondition(__CPROVER_is_zero_string(name),
"gethostbyname zero-termination of name argument");
#endif
(void)*name;

__CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool();
if(error) return 0;
Expand Down
61 changes: 33 additions & 28 deletions src/ansi-c/library/new.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,30 +72,32 @@ __CPROVER_bool __VERIFIER_nondet___CPROVER_bool();
inline void __delete(void *ptr)
{
__CPROVER_HIDE:;
// is it dynamic?
__CPROVER_precondition(ptr==0 || __CPROVER_DYNAMIC_OBJECT(ptr),
"delete argument must be dynamic object");
__CPROVER_precondition(__CPROVER_POINTER_OFFSET(ptr)==0,
"delete argument must have offset zero");

// catch double delete
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr, "double delete");

// catch people who call delete for objects allocated with new[]
__CPROVER_precondition(ptr==0 ||
__CPROVER_malloc_object!=ptr ||
!__CPROVER_malloc_is_new_array,
"delete of array object");

// If ptr is NULL, no operation is performed.
// This is a requirement by the standard, not generosity!
if(ptr!=0)
{
// is it dynamic?
__CPROVER_assert(__CPROVER_DYNAMIC_OBJECT(ptr),
"delete argument must be dynamic object");
__CPROVER_assert(__CPROVER_POINTER_OFFSET(ptr)==0,
"delete argument must have offset zero");

// catch double delete
__CPROVER_assert(__CPROVER_deallocated!=ptr, "double delete");

// catch people who call delete for objects allocated with new[]
__CPROVER_assert(__CPROVER_malloc_object!=ptr ||
!__CPROVER_malloc_is_new_array,
"delete of array object");

// non-deterministically record as deallocated
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
__CPROVER_deallocated=record?ptr:__CPROVER_deallocated;

// detect memory leaks
if(__CPROVER_memory_leak==ptr) __CPROVER_memory_leak=0;
if(__CPROVER_memory_leak==ptr)
__CPROVER_memory_leak=0;
}
}

Expand All @@ -108,22 +110,25 @@ inline void __delete_array(void *ptr)
__CPROVER_HIDE:;
// If ptr is NULL, no operation is performed.
// This is a requirement by the standard, not generosity!
if(ptr!=0)
{
// is it dynamic?
__CPROVER_assert(__CPROVER_DYNAMIC_OBJECT(ptr),
"delete argument must be dynamic object");
__CPROVER_assert(__CPROVER_POINTER_OFFSET(ptr)==0,
"delete argument must have offset zero");

// catch double delete
__CPROVER_assert(__CPROVER_deallocated!=ptr, "double delete");
// is it dynamic?
__CPROVER_precondition(ptr==0 || __CPROVER_DYNAMIC_OBJECT(ptr),
"delete argument must be dynamic object");
__CPROVER_precondition(ptr==0 || __CPROVER_POINTER_OFFSET(ptr)==0,
"delete argument must have offset zero");

// catch people who call delete[] for objects allocated with new
__CPROVER_assert(__CPROVER_malloc_object!=ptr ||
__CPROVER_malloc_is_new_array,
"delete[] of non-array object");
// catch double delete
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr,
"double delete");

// catch people who call delete[] for objects allocated with new
__CPROVER_precondition(ptr==0 ||
__CPROVER_malloc_object!=ptr ||
__CPROVER_malloc_is_new_array,
"delete[] of non-array object");

if(ptr!=0)
{
// non-deterministically record as deallocated
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
__CPROVER_deallocated=record?ptr:__CPROVER_deallocated;
Expand Down
34 changes: 18 additions & 16 deletions src/ansi-c/library/stdlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,24 +162,26 @@ inline void free(void *ptr)
__CPROVER_precondition(ptr==0 || __CPROVER_POINTER_OFFSET(ptr)==0,
"free argument has offset zero");

if(ptr!=0)
{
// catch double free
if(__CPROVER_deallocated==ptr)
__CPROVER_assert(0, "double free");
// catch double free
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr,
"double free");

// catch people who try to use free(...) for stuff
// allocated with new[]
__CPROVER_assert(__CPROVER_malloc_object!=ptr ||
!__CPROVER_malloc_is_new_array,
"free called for new[] object");
// catch people who try to use free(...) for stuff
// allocated with new[]
__CPROVER_precondition(ptr==0 ||
__CPROVER_malloc_object!=ptr ||
!__CPROVER_malloc_is_new_array,
"free called for new[] object");

if(ptr!=0)
{
// non-deterministically record as deallocated
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
if(record) __CPROVER_deallocated=ptr;

// detect memory leaks
if(__CPROVER_memory_leak==ptr) __CPROVER_memory_leak=0;
if(__CPROVER_memory_leak==ptr)
__CPROVER_memory_leak=0;
}
}

Expand All @@ -206,7 +208,7 @@ inline long strtol(const char *nptr, char **endptr, int base)
{
__CPROVER_HIDE:;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(nptr),
__CPROVER_precondition(__CPROVER_is_zero_string(nptr),
"zero-termination of argument of strtol");
#endif

Expand Down Expand Up @@ -329,7 +331,7 @@ inline char *getenv(const char *name)

(void)*name;
#ifdef __CPROVER_STRING_ABSTRACTION
__CPROVER_assert(__CPROVER_is_zero_string(name),
__CPROVER_precondition(__CPROVER_is_zero_string(name),
"zero-termination of argument of getenv");
#endif

Expand Down Expand Up @@ -367,6 +369,9 @@ inline void *realloc(void *ptr, __CPROVER_size_t malloc_size)
{
__CPROVER_HIDE:;

__CPROVER_precondition(ptr==0 || __CPROVER_DYNAMIC_OBJECT(ptr),
"realloc argument is dynamic object");

// if ptr is NULL, this behaves like malloc
if(ptr==0)
return malloc(malloc_size);
Expand All @@ -379,9 +384,6 @@ inline void *realloc(void *ptr, __CPROVER_size_t malloc_size)
return malloc(1);
}

__CPROVER_assert(__CPROVER_DYNAMIC_OBJECT(ptr),
"realloc argument is dynamic object");

// this shouldn't move if the new size isn't bigger
void *res;
res=malloc(malloc_size);
Expand Down
Loading

0 comments on commit 7b5dd17

Please sign in to comment.