You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1832 lines
44 KiB
1832 lines
44 KiB
/*
|
|
* Copyright (c) 2009 - 2013 Monoidics ltd.
|
|
* Copyright (c) 2013 - present Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
// Basic modelling of some libc functions
|
|
|
|
// prevent _FORTIFY_SOURCE from changing some function prototypes
|
|
// https://securityblog.redhat.com/2014/03/26/fortify-and-you/
|
|
#ifdef _FORTIFY_SOURCE
|
|
#undef _FORTIFY_SOURCE
|
|
#endif
|
|
#define _FORTIFY_SOURCE 0
|
|
|
|
#ifdef __APPLE__ // disable block instructions on mac
|
|
#ifdef __BLOCKS__
|
|
#undef __BLOCKS__
|
|
#endif
|
|
#ifdef _POSIX_C_SOURCE
|
|
#undef _POSIX_C_SOURCE
|
|
#endif
|
|
#endif
|
|
|
|
#include "infer_builtins.h"
|
|
|
|
// use c++ headers if in C++ mode - they are mostly same as C headers,
|
|
// but there are some subtle differences from time to time. For example,
|
|
// 'getc' may be defined as macro in stdio.h, and a function in cstdio
|
|
#ifdef __cplusplus
|
|
#include <climits>
|
|
#include <clocale>
|
|
#include <csetjmp>
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <csignal>
|
|
#else
|
|
#include <limits.h>
|
|
#include <locale.h>
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#include <dirent.h>
|
|
#include <pwd.h>
|
|
#include <pthread.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#ifdef __APPLE__ // includes for statfs are system-dependent
|
|
#include <sys/mount.h>
|
|
#include <sys/param.h>
|
|
#else
|
|
#include <sys/statfs.h>
|
|
#endif
|
|
|
|
#ifndef __APPLE__
|
|
/* struct __dirstream is abstract on Linux, at least on Debian 8.0
|
|
we need it to be concrete to model closedir (5) */
|
|
/* dummy __dirstream structure */
|
|
struct __dirstream {
|
|
int fd;
|
|
};
|
|
#endif
|
|
|
|
// this condition checks whether to use C++ const-overloads of C functions
|
|
// for example strchr.
|
|
#if defined(__CORRECT_ISO_CPP_STRING_H_PROTO) || \
|
|
defined(_LIBCPP_PREFERRED_OVERLOAD)
|
|
#define INFER_USE_CPP_CONST_OVERLOAD
|
|
#endif
|
|
|
|
// modelling of errno
|
|
// errno expands to different function calls on mac or other systems
|
|
// the function call returns the address of a global variable called "errno"
|
|
extern int errno;
|
|
#ifdef __APPLE__
|
|
#define __ERRNO_FUN_NAME __error
|
|
#else
|
|
#define __ERRNO_FUN_NAME __errno_location
|
|
#endif
|
|
int* __ERRNO_FUN_NAME() { return &errno; }
|
|
|
|
// the strings s1 and s2 need to be allocated
|
|
// check that s2 fits inside s1
|
|
char* strcpy(char* s1, const char* s2) {
|
|
int size1;
|
|
int size2;
|
|
__infer_set_flag("ignore_return",
|
|
""); // no warnings if the return value is ignored
|
|
__require_allocated_array(s1);
|
|
size1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION(size2 > size1);
|
|
return s1;
|
|
}
|
|
|
|
// the string s must be allocated; return the result of malloc with the same
|
|
// size
|
|
char* strdup(const char* s) {
|
|
int size;
|
|
__require_allocated_array(s);
|
|
size = __get_array_length(s);
|
|
return (char*)malloc(size);
|
|
}
|
|
|
|
// the strings s1 and s2 need to be allocated
|
|
// check that s2 fits inside s1
|
|
char* strcat(char* s1, const char* s2) {
|
|
int size1;
|
|
int size2;
|
|
__require_allocated_array(s1);
|
|
size1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION(size2 > size1);
|
|
return s1;
|
|
}
|
|
|
|
// C++ has two versions of strchr:
|
|
// http://www.cplusplus.com/reference/cstring/strchr/
|
|
// C has one version of strchr/strrchr with different signature
|
|
|
|
// The string s must be allocated
|
|
// nondeterministically return 0 or a pointer inside the buffer
|
|
#ifndef INFER_USE_CPP_CONST_OVERLOAD
|
|
char* strchr(const char* s, int c) {
|
|
#else
|
|
// This overload is commented out on purpose.
|
|
// Standard headers define both functions with same __asm symbol which
|
|
// means they cannot be both defined. On the other hand, since both of them
|
|
// have same __asm symbol, mangling will be the same and infer will have
|
|
// specs for both functions (they both will have the same name)
|
|
// NOTE: this was tested on couple of systems, it may not be always true.
|
|
// const char* strchr(const char* s, int c) throw() { return strchr((char*)s,
|
|
// c); }
|
|
|
|
char* strchr(char* s, int c) throw() {
|
|
#endif
|
|
int size;
|
|
int nondet;
|
|
int offset;
|
|
nondet = __infer_nondet_int();
|
|
offset = __infer_nondet_int();
|
|
|
|
__require_allocated_array(s);
|
|
size = __get_array_length(s);
|
|
if (nondet)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size);
|
|
return (char*)s + offset;
|
|
}
|
|
|
|
// modelled like strchr
|
|
#ifndef INFER_USE_CPP_CONST_OVERLOAD
|
|
char* strrchr(const char* s, int c) { return strchr(s, c); }
|
|
#else
|
|
// This overload is commented out on purpose. Look at strchr() for more info.
|
|
/*const char* strrchr(const char* s, int c) throw() {
|
|
return strchr((char*)s, c);
|
|
}*/
|
|
|
|
char* strrchr(char* s, int c) throw() { return strchr(s, c); }
|
|
#endif
|
|
|
|
// s1 and s2 must be allocated.
|
|
// return a non-deterministic integer
|
|
int strcmp(const char* s1, const char* s2) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
|
|
__require_allocated_array(s1);
|
|
__require_allocated_array(s2);
|
|
return res;
|
|
}
|
|
|
|
// the string s must be allocated
|
|
// return the size of the buffer - 1
|
|
size_t strlen(const char* s) {
|
|
int size;
|
|
__require_allocated_array(s);
|
|
size = __get_array_length(s);
|
|
return size - 1;
|
|
}
|
|
|
|
// s must be allocated
|
|
// return s
|
|
char* strlwr(char* s) {
|
|
__require_allocated_array(s);
|
|
return s;
|
|
}
|
|
|
|
// s1 and s2 must be allocated
|
|
// n should not be greater than the size of s1 or s2
|
|
// return s1
|
|
char* strncat(char* s1, const char* s2, size_t n) {
|
|
int size_s1;
|
|
int size_s2;
|
|
__require_allocated_array(s1);
|
|
size_s1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size_s2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2));
|
|
return s1;
|
|
}
|
|
|
|
// s1 and s2 must be allocated
|
|
// n should not be greater than the size of s1 or s2
|
|
// return a non-deterministic integer
|
|
int strncmp(const char* s1, const char* s2, size_t n) {
|
|
int size_s1;
|
|
int size_s2;
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
__require_allocated_array(s1);
|
|
size_s1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size_s2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2));
|
|
return res;
|
|
}
|
|
|
|
// the strings s1 and s2 need to be allocated
|
|
// check that n characters fit in s1 (because even if s2 is shorter than n, null
|
|
// characters are appended to s1)
|
|
char* strncpy(char* s1, const char* s2, size_t n) {
|
|
int size1;
|
|
__infer_set_flag("ignore_return",
|
|
""); // no warnings if the return value is ignored
|
|
__require_allocated_array(s1);
|
|
size1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
INFER_EXCLUDE_CONDITION(n > size1);
|
|
return s1;
|
|
}
|
|
|
|
#ifndef INFER_USE_CPP_CONST_OVERLOAD
|
|
char* strpbrk(const char* s1, const char* s2) {
|
|
#else
|
|
// This overload is commented out on purpose. Look at strchr() for more info.
|
|
/*const char* strpbrk(const char* s1, const char* s2) throw() {
|
|
return strpbrk((char*)s1, s2);
|
|
}*/
|
|
|
|
char* strpbrk(char* s1, const char* s2) throw() {
|
|
#endif
|
|
int size1;
|
|
int nondet;
|
|
int offset;
|
|
nondet = __infer_nondet_int();
|
|
offset = __infer_nondet_int();
|
|
__require_allocated_array(s1);
|
|
size1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
if (nondet)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size1);
|
|
return (char*)s1 + offset;
|
|
}
|
|
|
|
// s1 and s2 must be allocated.
|
|
// return an integer between 0 ans the size of s1
|
|
size_t strspn(const char* s1, const char* s2) {
|
|
int size_s1;
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
__require_allocated_array(s1);
|
|
size_s1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
INFER_EXCLUDE_CONDITION(res < 0 || res > size_s1);
|
|
return res;
|
|
}
|
|
|
|
#ifndef INFER_USE_CPP_CONST_OVERLOAD
|
|
char* strstr(const char* s1, const char* s2) {
|
|
#else
|
|
// This overload is commented out on purpose. Look at strchr() for more info.
|
|
/*const char* strstr(const char* s1, const char* s2) throw() {
|
|
return strstr((char*)s1, s2);
|
|
}*/
|
|
|
|
char* strstr(char* s1, const char* s2) throw() {
|
|
#endif
|
|
int size1, size2;
|
|
int nondet;
|
|
int offset;
|
|
nondet = __infer_nondet_int();
|
|
offset = __infer_nondet_int();
|
|
__require_allocated_array(s1);
|
|
size1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
if (nondet)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size1);
|
|
return (char*)s1 + offset;
|
|
}
|
|
|
|
// modeled using strtoul
|
|
double strtod(const char* str, char** endptr) {
|
|
return (double)strtoul(str, endptr, 0);
|
|
}
|
|
|
|
// modeled like strtoul
|
|
long strtol(const char* str, char** endptr, int base) {
|
|
return (long)strtoul(str, endptr, base);
|
|
}
|
|
|
|
// the string s must be allocated
|
|
// assign to endptr a pointer somewhere inside the string str
|
|
// result is nondeterministic
|
|
unsigned long strtoul(const char* str, char** endptr, int base) {
|
|
int size;
|
|
int offset;
|
|
int res;
|
|
__require_allocated_array(str);
|
|
size = __get_array_length(str);
|
|
offset = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size);
|
|
if (endptr)
|
|
*endptr = (char*)(str + offset);
|
|
res = __infer_nondet_int();
|
|
int errno_val = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(errno_val < 0);
|
|
errno = errno_val;
|
|
return res;
|
|
}
|
|
|
|
// s must be allocated
|
|
// return s
|
|
char* strupr(char* s) {
|
|
__require_allocated_array(s);
|
|
return s;
|
|
}
|
|
|
|
// the array s must be allocated
|
|
// n should not be greater than the size of s
|
|
// nondeterministically return 0 or a pointer within the first n elements of s
|
|
#ifndef INFER_USE_CPP_CONST_OVERLOAD
|
|
void* memchr(const void* s, int c, size_t n) {
|
|
#else
|
|
// This overload is commented out on purpose. Look at strchr() for more info.
|
|
// const void* memchr(const void* s, int c, size_t n) throw() {
|
|
// return memchr((void*)s, c, n);
|
|
//}
|
|
|
|
void* memchr(void* s, int c, size_t n) throw() {
|
|
#endif
|
|
int size;
|
|
int nondet;
|
|
int offset;
|
|
nondet = __infer_nondet_int();
|
|
offset = __infer_nondet_int();
|
|
__require_allocated_array(s);
|
|
size = __get_array_length(s);
|
|
INFER_EXCLUDE_CONDITION(n > size);
|
|
if (nondet)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= n);
|
|
return (char*)s + offset;
|
|
}
|
|
|
|
// s1 and s2 must be allocated
|
|
// n should not be greater than the size of s1 or s2
|
|
// return a non-deterministic integer
|
|
int memcmp(const void* s1, const void* s2, size_t n) {
|
|
int size_s1;
|
|
int size_s2;
|
|
__require_allocated_array(s1);
|
|
size_s1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size_s2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2));
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// s1 and s2 must be allocated
|
|
// n must be between 0 and the minumum of the sizes of s1 and s2
|
|
void* memcpy(void* s1, const void* s2, size_t n) {
|
|
int size_s1;
|
|
int size_s2;
|
|
__infer_set_flag("ignore_return",
|
|
""); // no warnings if the return value is ignored
|
|
__require_allocated_array(s1);
|
|
size_s1 = __get_array_length(s1);
|
|
__require_allocated_array(s2);
|
|
size_s2 = __get_array_length(s2);
|
|
INFER_EXCLUDE_CONDITION((n < 0) || (n > size_s1) || (n > size_s2));
|
|
return s1;
|
|
}
|
|
|
|
// modeld using memcpy
|
|
void* memmove(void* s1, const void* s2, size_t n) {
|
|
__infer_set_flag("ignore_return",
|
|
""); // no warnings if the return value is ignored
|
|
return memcpy(s1, s2, n);
|
|
}
|
|
|
|
// s needs to be allocated
|
|
// n should not be greater than the size of s
|
|
void* memset(void* s, int c, size_t n) {
|
|
int size_s;
|
|
__infer_set_flag("ignore_return",
|
|
""); // no warnings if the return value is ignored
|
|
__require_allocated_array(s);
|
|
size_s = __get_array_length(s);
|
|
INFER_EXCLUDE_CONDITION(n > size_s);
|
|
return s;
|
|
}
|
|
|
|
// return a nondeterministic double
|
|
double atof(const char* str) { return __infer_nondet_double(); }
|
|
|
|
// return a nondeterministic value between INT_MIN and INT_MAX
|
|
int atoi(const char* str) {
|
|
int retu = INT_MAX;
|
|
int retl = INT_MIN;
|
|
int ret;
|
|
if (__infer_nondet_int())
|
|
ret = retu;
|
|
else
|
|
ret = retl;
|
|
return ret;
|
|
}
|
|
|
|
// modeled using malloc and set file attribute
|
|
FILE* fopen(const char* filename, const char* mode) {
|
|
FILE* ret;
|
|
ret = (FILE*)malloc(sizeof(FILE));
|
|
if (ret)
|
|
__set_file_attribute(ret);
|
|
return ret;
|
|
}
|
|
|
|
// modeled using fopen
|
|
FILE* tmpfile(void) { return fopen("foo", ""); }
|
|
|
|
// use a global variable to model the return value of tmpnam
|
|
extern char* _tmpnam_global;
|
|
// return NULL, or if s is NULL return a global variable, otherwise check that s
|
|
// has size at least L_tmpnam and return s
|
|
char* tmpnam(char* s) {
|
|
int success;
|
|
int size;
|
|
|
|
success = __infer_nondet_int();
|
|
if (!success)
|
|
return NULL;
|
|
if (s) {
|
|
__require_allocated_array(s);
|
|
size = __get_array_length(s);
|
|
INFER_EXCLUDE_CONDITION(size < L_tmpnam);
|
|
return s;
|
|
} else
|
|
return _tmpnam_global;
|
|
}
|
|
|
|
// nondeterministically return NULL or the original stream
|
|
FILE* freopen(const char* __restrict filename,
|
|
const char* __restrict mode,
|
|
FILE* __restrict stream) {
|
|
int n;
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return NULL;
|
|
else
|
|
return stream;
|
|
}
|
|
|
|
// modeled using free, can return EOF
|
|
int fclose(FILE* stream) {
|
|
int n;
|
|
free(stream);
|
|
n = __infer_nondet_int();
|
|
if (n > 0)
|
|
return 0;
|
|
else
|
|
return EOF;
|
|
}
|
|
|
|
// modeled using malloc and set file attribute
|
|
// return the allocated ptr - 1 if malloc succeeds, otherwise return -1
|
|
int open(const char* path, int oflag, ...) {
|
|
int* ret = (int*)malloc(sizeof(int));
|
|
if (ret) {
|
|
__set_file_attribute(ret);
|
|
INFER_EXCLUDE_CONDITION(ret < (int*)1); // force result to be > 0
|
|
return (size_t)ret;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// modeled using free, can return -1
|
|
int close(int fildes) {
|
|
int n;
|
|
if (fildes != -1)
|
|
free((int*)(long)fildes);
|
|
n = __infer_nondet_int();
|
|
if (n > 0)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// modeled as close followed by fopen
|
|
FILE* fdopen(int fildes, const char* mode) {
|
|
close(fildes);
|
|
return fopen("foo", mode);
|
|
}
|
|
|
|
// modeled using fdopen
|
|
FILE* gzdopen(int fildes, const char* mode) { return fdopen(fildes, mode); }
|
|
|
|
// return nonteterministically 0 or -1
|
|
// requires stream to be allocated
|
|
int fseek(FILE* stream, long int offset, int whence) {
|
|
int n;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// return nondeterministically a nonnegative value or -1
|
|
// requires stream to be allocated
|
|
long int ftell(FILE* stream) {
|
|
int n;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
n = __infer_nondet_int();
|
|
if (n >= 0)
|
|
return n;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// on success return str otherwise null
|
|
// requires stream to be allocated
|
|
char* fgets(char* str, int num, FILE* stream) {
|
|
int n;
|
|
int size1;
|
|
FILE tmp;
|
|
|
|
tmp = *stream;
|
|
n = __infer_nondet_int();
|
|
|
|
if (n > 0) {
|
|
__require_allocated_array(str);
|
|
size1 = __get_array_length(str);
|
|
INFER_EXCLUDE_CONDITION(num > size1);
|
|
return str;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
// string s must be allocated; return nondeterministically s or NULL
|
|
char* gets(char* s) {
|
|
int n;
|
|
|
|
__require_allocated_array(s);
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return s;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// str must be allocated, return a nondeterministic value
|
|
int puts(const char* str) {
|
|
__require_allocated_array(str);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// modeled using puts
|
|
// require the stream to be allocated
|
|
int fputs(const char* str, FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return puts(str);
|
|
}
|
|
|
|
// return a nondeterministic value
|
|
// requires stream to be allocated
|
|
int getc(FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// return a nondeterministic value
|
|
// requires stream to be allocated
|
|
int fgetc(FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// return nondeterministically c or EOF
|
|
// requires stream to be allocated
|
|
int ungetc(int c, FILE* stream) {
|
|
int n;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return c;
|
|
else
|
|
return EOF;
|
|
}
|
|
|
|
// modeled like putc
|
|
// requires stream to be allocated
|
|
int fputc(int c, FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return putc(c, stream);
|
|
}
|
|
|
|
// on success return buffer otherwise null
|
|
char* getcwd(char* buffer, size_t size) {
|
|
int n;
|
|
int size_buf;
|
|
n = __infer_nondet_int();
|
|
|
|
if (n > 0) {
|
|
__require_allocated_array(buffer);
|
|
size_buf = __get_array_length(buffer);
|
|
INFER_EXCLUDE_CONDITION(size > size_buf);
|
|
return buffer;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
// return nonteterministically 0 or -1
|
|
int rename(const char* old, const char* new_) {
|
|
int n;
|
|
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// modeled as skip
|
|
// requires stream to be allocated
|
|
void rewind(FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
}
|
|
|
|
// modeled as exit()
|
|
void longjmp(jmp_buf env, int val) { exit(0); }
|
|
|
|
// modeled as skip.
|
|
// If sleep() returns because the requested time has elapsed,
|
|
// the value returned shall be 0. If sleep() returns due to delivery of a
|
|
// signal,
|
|
// the return value shall be the "unslept" amount (the requested time minus the
|
|
// time actually slept) in seconds.
|
|
unsigned sleep(unsigned seconds) {
|
|
int n;
|
|
n = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(n < 0);
|
|
return n;
|
|
}
|
|
|
|
#ifdef __CYGWIN__ // define __WAIT_STATUS as int * on cygwin
|
|
#define __WAIT_STATUS int*
|
|
#endif
|
|
#ifdef __APPLE__ // define __WAIT_STATUS as int * on mac
|
|
#define __WAIT_STATUS int*
|
|
#endif
|
|
|
|
// glibc 2.24 did away with 'union wait' and replaced it with int*.
|
|
// Hence, we re-define __WAIT_STATUS if glibc is >= 2.24.
|
|
#ifndef __GLIBC_PREREQ
|
|
#define __GLIBC_PREREQ(x, y) 0
|
|
#endif
|
|
|
|
#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 24)
|
|
#define __WAIT_STATUS int*
|
|
#endif
|
|
|
|
// the waiting is modeled as skip. Then the return value is a random value of a
|
|
// process or
|
|
// -1 in case of an error
|
|
pid_t wait(__WAIT_STATUS stat_loc) {
|
|
int n;
|
|
pid_t tmp;
|
|
n = __infer_nondet_int();
|
|
tmp = __infer_nondet_int();
|
|
if (n > 0)
|
|
return tmp;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
#ifndef __cplusplus
|
|
// return a nondeterministic pointer
|
|
void (*signal(int sig, void (*func)(int)))(int) {
|
|
void (*res)(int) = __infer_nondet_ptr();
|
|
return res;
|
|
};
|
|
#endif
|
|
|
|
// modelled as exit
|
|
void pthread_exit(void* value_ptr) { exit(0); };
|
|
|
|
// INTENDED SEMANTICS: The setitimer() function shall set the timer specified by
|
|
// which
|
|
// to the value specified in the structure pointed to by value, and if ovalue is
|
|
// not a null pointer,
|
|
// store the previous value of the timer in the structure pointed to by ovalue.
|
|
int setitimer(int which,
|
|
const struct itimerval* __restrict value,
|
|
struct itimerval* __restrict ovalue) {
|
|
int n;
|
|
int tmp;
|
|
n = __infer_nondet_int();
|
|
tmp = __infer_nondet_int();
|
|
// not sure about this assignment.
|
|
// it should somehow change the value of the timer which.
|
|
// But which is just an int, so it looks like this is useless
|
|
which = tmp;
|
|
if (n > 0)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// pause returns only when a signal is received
|
|
// the return value is always -1
|
|
int pause(void) { return -1; }
|
|
|
|
// modeled with nondeterministic value n
|
|
pid_t fork(void) { return __infer_nondet_int(); }
|
|
|
|
// allocate memory directly, and return -1 if malloc fails.
|
|
int shmget(key_t key, size_t size, int shmflg) {
|
|
void* res = malloc(size);
|
|
if (!res)
|
|
return -1;
|
|
return (long)res;
|
|
}
|
|
|
|
// simply return the first parameter
|
|
void* shmat(int shmid, const void* shmaddr, int shmflg) {
|
|
return (void*)(long)shmid;
|
|
}
|
|
|
|
// return a non-deterministic value
|
|
int shmdt(const void* shmaddr) { return __infer_nondet_int(); }
|
|
|
|
// if the command is IPC_RMID free the first parameter; return a
|
|
// non-deterministic value
|
|
int shmctl(int shmid, int cmd, struct shmid_ds* buf) {
|
|
int n;
|
|
void* shmaddr;
|
|
n = __infer_nondet_int();
|
|
shmaddr = (void*)(long)shmid;
|
|
if (cmd == IPC_RMID)
|
|
free(shmaddr);
|
|
return n;
|
|
}
|
|
|
|
void* realloc(void* ptr, size_t size) {
|
|
if (ptr == 0) { // if ptr in NULL, behave as malloc
|
|
return malloc(size);
|
|
}
|
|
int can_enlarge;
|
|
__require_allocated_array(ptr);
|
|
can_enlarge = __infer_nondet_int(); // nondeterministically choose whether the
|
|
// current block can be enlarged
|
|
if (can_enlarge) {
|
|
__set_array_length(ptr, size); // enlarge the block
|
|
return ptr;
|
|
}
|
|
int* newblock = (int*)malloc(size);
|
|
if (newblock) {
|
|
free(ptr);
|
|
return newblock;
|
|
} else { // if new allocation fails, do not free the old block
|
|
return newblock;
|
|
}
|
|
}
|
|
|
|
// modelled as a call to malloc
|
|
void* calloc(size_t nmemb, size_t size) { return malloc(nmemb * size); }
|
|
|
|
// character functions from ctype.h
|
|
// all modelled as returning a nondeterministic value
|
|
int isalnum(int x) { return __infer_nondet_int(); }
|
|
int isalpha(int x) { return __infer_nondet_int(); }
|
|
int isblank(int x) { return __infer_nondet_int(); }
|
|
int iscntrl(int x) { return __infer_nondet_int(); }
|
|
int isdigit(int x) { return __infer_nondet_int(); }
|
|
int isgraph(int x) { return __infer_nondet_int(); }
|
|
int islower(int x) { return __infer_nondet_int(); }
|
|
int isprint(int x) { return __infer_nondet_int(); }
|
|
int ispunct(int x) { return __infer_nondet_int(); }
|
|
int isspace(int x) { return __infer_nondet_int(); }
|
|
int isupper(int x) { return __infer_nondet_int(); }
|
|
int isxdigit(int x) { return __infer_nondet_int(); }
|
|
int tolower(int x) { return __infer_nondet_int(); }
|
|
int toupper(int x) { return __infer_nondet_int(); }
|
|
int isascii(int x) { return __infer_nondet_int(); }
|
|
int toascii(int x) { return __infer_nondet_int(); }
|
|
|
|
// modeled as skip. n>0 models success.
|
|
// Upon successful completion a non-negative integer, namely the file
|
|
// descriptor, shall be returned;
|
|
// otherwise, -1 shall be returned.
|
|
int dup(int fildes) {
|
|
int n;
|
|
n = __infer_nondet_int();
|
|
if (n > 0)
|
|
return fildes;
|
|
else
|
|
return -1;
|
|
};
|
|
|
|
// modeled as skip.
|
|
// The getuid() function shall always be successful and no return value is
|
|
// reserved to indicate the error.
|
|
uid_t getuid(void) { return __infer_nondet_int(); };
|
|
|
|
// modeled as skip
|
|
// The getpid() function shall always be successful and no return value is
|
|
// reserved to indicate an error.
|
|
pid_t getpid(void) { return __infer_nondet_int(); };
|
|
|
|
// modeled as skip.
|
|
// success is modeled by n>0, if lseek fails (off_t)-1 should be returned.
|
|
off_t lseek(int fildes, off_t offset, int whence) {
|
|
int n;
|
|
off_t tmp;
|
|
n = __infer_nondet_int();
|
|
tmp = __infer_nondet_int();
|
|
|
|
if (n > 0)
|
|
return tmp;
|
|
else
|
|
return (off_t)-1;
|
|
};
|
|
|
|
// modeled using malloc and set file attribute
|
|
DIR* opendir(const char* dirname) {
|
|
DIR* ret;
|
|
ret = (DIR*)malloc(sizeof(void*));
|
|
if (ret)
|
|
__set_file_attribute(ret);
|
|
return ret;
|
|
}
|
|
|
|
// modeled using free, can return EOF
|
|
int closedir(DIR* dirp) {
|
|
DIR tmp = *dirp;
|
|
int n;
|
|
n = __infer_nondet_int();
|
|
free(dirp);
|
|
if (n > 0)
|
|
return 0;
|
|
else
|
|
return EOF;
|
|
}
|
|
|
|
// use a global variable to model the return value of readdir
|
|
extern struct dirent* _dirent_global;
|
|
// dirp must be allocated
|
|
// return 0 or the allocated pointerq _dirent_global, nondeterministically
|
|
struct dirent* readdir(DIR* dirp) {
|
|
int nondet;
|
|
struct dirent* ret = _dirent_global;
|
|
__require_allocated_array(dirp);
|
|
nondet = __infer_nondet_int();
|
|
if (nondet)
|
|
return 0;
|
|
return ret;
|
|
}
|
|
|
|
// use a global variable to model the return value of getenv
|
|
extern char* _getenv_global;
|
|
// string name must be allocated
|
|
// return 0 or the allocated string _getenv_global, nondeterministically
|
|
char* getenv(const char* name) {
|
|
int nondet;
|
|
__require_allocated_array(name);
|
|
__require_allocated_array(_getenv_global);
|
|
nondet = __infer_nondet_int();
|
|
if (nondet)
|
|
return 0;
|
|
return _getenv_global;
|
|
}
|
|
|
|
// use a global variable to model the return value of setlocale
|
|
extern char* _locale_global;
|
|
// string locale must be allocated
|
|
// return 0 or the allocated string _locale_global, nondeterministically
|
|
char* setlocale(int category, const char* locale) {
|
|
int nondet;
|
|
__require_allocated_array(locale);
|
|
__require_allocated_array(_locale_global);
|
|
nondet = __infer_nondet_int();
|
|
if (nondet)
|
|
return 0;
|
|
return _locale_global;
|
|
}
|
|
|
|
// use a global variable to model the return value of localeconv
|
|
extern struct lconv* _lconv_global;
|
|
// return the allocated pointer _lconv_global
|
|
struct lconv* localeconv() {
|
|
int nondet;
|
|
struct lconv tmp;
|
|
tmp = *_lconv_global;
|
|
return _lconv_global;
|
|
}
|
|
|
|
// use a global variable to model the return value of localtime
|
|
extern struct tm* _tm_global;
|
|
// return nondeterministically NULL or the global variable _tm_global
|
|
struct tm* localtime(const time_t* clock) {
|
|
int fail;
|
|
|
|
fail = __infer_nondet_int();
|
|
if (fail)
|
|
return NULL;
|
|
else
|
|
return _tm_global;
|
|
}
|
|
|
|
// return nondeterministically NULL or the global variable _tm_global
|
|
struct tm* gmtime(const time_t* timer) {
|
|
int fail;
|
|
|
|
fail = __infer_nondet_int();
|
|
if (fail)
|
|
return NULL;
|
|
else
|
|
return _tm_global;
|
|
}
|
|
|
|
// use a global variable to model the return value of asctime
|
|
extern char* _asctime_global;
|
|
// return the global variable _asctime_global
|
|
char* asctime(const struct tm* timeptr) { return _asctime_global; }
|
|
|
|
// modelled using asctime and localtime
|
|
char* ctime(const time_t* clock) { return asctime(localtime(clock)); }
|
|
|
|
// return a nondeterministic double
|
|
double difftime(time_t time1, time_t time0) { return __infer_nondet_double(); }
|
|
|
|
// return a nondeterministic nonnegative value or -1
|
|
time_t mktime(struct tm* timeptr) {
|
|
time_t res;
|
|
res = __infer_nondet_time_t();
|
|
INFER_EXCLUDE_CONDITION(res < -1);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative value or -1
|
|
clock_t clock() {
|
|
clock_t res;
|
|
res = __infer_nondet_clock_t();
|
|
INFER_EXCLUDE_CONDITION(res < -1);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative value
|
|
size_t strftime(char* __restrict s,
|
|
size_t maxsize,
|
|
const char* __restrict format,
|
|
const struct tm* __restrict timeptr) {
|
|
size_t res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic value of type time_t
|
|
time_t time(time_t* tloc) {
|
|
time_t t;
|
|
t = __infer_nondet_time_t();
|
|
if (tloc)
|
|
*tloc = t;
|
|
return t;
|
|
}
|
|
|
|
// use a global variable to model the return value of getpwuid
|
|
extern struct passwd* _getpwuid_global;
|
|
// return either NULL or the global variable _getpwuid_global
|
|
struct passwd* getpwuid(uid_t uid) {
|
|
int found;
|
|
found = __infer_nondet_int();
|
|
if (found)
|
|
return _getpwuid_global;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// use a global variable to model the return value of getpwent
|
|
extern struct passwd* _getpwent_global;
|
|
// return either NULL or the global variable _getpwent_global
|
|
struct passwd* getpwent(void) {
|
|
int found;
|
|
found = __infer_nondet_int();
|
|
if (found)
|
|
return _getpwent_global;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// use a global variable to model the return value of getpwnam
|
|
extern struct passwd* _getpwnam_global;
|
|
// login must be allocated
|
|
// return either NULL or the global variable _getpnam_global
|
|
struct passwd* getpwnam(const char* login) {
|
|
int found;
|
|
__require_allocated_array(login);
|
|
found = __infer_nondet_int();
|
|
if (found)
|
|
return _getpwnam_global;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// nondeterministically return 0 (failure) or 1 (success)
|
|
int setpassent(int stayopen) {
|
|
int success;
|
|
success = __infer_nondet_int();
|
|
if (success)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// modled as skip
|
|
void setpwent(void) {}
|
|
|
|
// modled as skip
|
|
void endpwent(void) {}
|
|
|
|
// use a global variable to model the return value of getlogin
|
|
extern char* _getlogin_global;
|
|
// string name must be allocated
|
|
// return 0 or the allocated string _getlogin_global, nondeterministically
|
|
char* getlogin() {
|
|
int size;
|
|
int nondet;
|
|
__require_allocated_array(_getlogin_global);
|
|
nondet = __infer_nondet_int();
|
|
if (nondet)
|
|
return 0;
|
|
return _getlogin_global;
|
|
}
|
|
|
|
int setlogin(const char* name) {
|
|
int success;
|
|
__require_allocated_array(name);
|
|
success = __infer_nondet_int();
|
|
if (success) {
|
|
strcpy(_getlogin_global, name);
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
// use a global variable to model the return value of getpass
|
|
extern char* _getpass_global;
|
|
// prompt must be allocated
|
|
// return the global variable _getpass_global, which must be allocated
|
|
char* getpass(const char* prompt) {
|
|
__require_allocated_array(prompt);
|
|
__require_allocated_array(_getpass_global);
|
|
return _getpass_global;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
int printf(const char* format, ...) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
// requires stream to be allocated
|
|
int fprintf(FILE* stream, const char* format, ...) {
|
|
int res;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
int snprintf(char* __restrict s, size_t n, const char* __restrict format, ...) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// s must be allocated
|
|
// return a nondeterministic nonnegative integer
|
|
int sprintf(char* s, const char* format, ...) {
|
|
int res;
|
|
__require_allocated_array(s);
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
// requires stream to be allocated
|
|
int vfprintf(FILE* stream, const char* format, va_list arg) {
|
|
int res;
|
|
FILE tmp;
|
|
|
|
tmp = *stream;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
int vsprintf(char* s, const char* format, va_list arg) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
int vsnprintf(char* s, size_t n, const char* format, va_list arg) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// return a nondeterministic nonnegative integer
|
|
int vprintf(const char* format, va_list arg) {
|
|
int res;
|
|
res = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(res < 0);
|
|
return res;
|
|
}
|
|
|
|
// forces path to be allocated
|
|
// return nondeterministically 0 or -1
|
|
int utimes(const char* path, const struct timeval times[2]) {
|
|
int success = __infer_nondet_int();
|
|
|
|
__require_allocated_array(path);
|
|
// return random result
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
// forces filename to be allocated
|
|
// return nondeterministically 0 or -1
|
|
int unlink(const char* filename) {
|
|
int success = __infer_nondet_int();
|
|
__require_allocated_array(filename);
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
// return nondeterministically 0 or -1
|
|
int usleep(useconds_t useconds) {
|
|
int success = __infer_nondet_int();
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
// dst and src must be allocated
|
|
// return an integer between 0 and size
|
|
size_t strlcpy(char* dst, const char* src, size_t size) {
|
|
int size_dst;
|
|
int res;
|
|
|
|
res = __infer_nondet_int();
|
|
|
|
// force src to be allocated
|
|
__require_allocated_array(src);
|
|
|
|
// force dst to be allocated for at least size
|
|
__require_allocated_array(dst);
|
|
size_dst = __get_array_length(dst);
|
|
INFER_EXCLUDE_CONDITION(size > size_dst);
|
|
|
|
INFER_EXCLUDE_CONDITION(res > size || res < 0);
|
|
|
|
return res;
|
|
}
|
|
|
|
// dst and src must be allocated
|
|
// return an integer between 0 and size
|
|
size_t strlcat(char* dst, const char* src, size_t size) {
|
|
int size_dst;
|
|
int res;
|
|
|
|
res = __infer_nondet_int();
|
|
|
|
// force src to be allocated
|
|
__require_allocated_array(src);
|
|
|
|
// force dst to be allocated for at least size
|
|
__require_allocated_array(dst);
|
|
size_dst = __get_array_length(dst);
|
|
INFER_EXCLUDE_CONDITION(size > size_dst);
|
|
|
|
INFER_EXCLUDE_CONDITION(res > size || res < 0);
|
|
|
|
return res;
|
|
}
|
|
|
|
// path must be allocated
|
|
// assign nonteterministically to the contents of buf
|
|
// return 0 or -1
|
|
int statfs(const char* path, struct statfs* buf) {
|
|
int success;
|
|
|
|
success = __infer_nondet_int();
|
|
|
|
// force path to be allocated
|
|
__require_allocated_array(path);
|
|
|
|
struct statfs s; // uninitialized struct statfs
|
|
*buf = s;
|
|
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
// path must be allocated
|
|
// assign nonteterministically to the contents of buf
|
|
// return 0 or -1
|
|
int stat(const char* path, struct stat* buf) {
|
|
int success;
|
|
|
|
success = __infer_nondet_int();
|
|
|
|
// force path to be allocated
|
|
__require_allocated_array(path);
|
|
|
|
struct stat s; // uninitialized struct stat
|
|
*buf = s;
|
|
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
int remove(const char* path) {
|
|
int success;
|
|
|
|
// force path to be allocated
|
|
__require_allocated_array(path);
|
|
|
|
success = __infer_nondet_int();
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
char* readline(const char* prompt) {
|
|
char* ret;
|
|
int size;
|
|
|
|
// force prompt to be allocated when not null
|
|
if (prompt != NULL) {
|
|
__require_allocated_array(prompt);
|
|
}
|
|
|
|
// return random string of positive size
|
|
size = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(size < 0);
|
|
|
|
ret = (char*)malloc(sizeof(size));
|
|
return ret;
|
|
}
|
|
|
|
long random(void) {
|
|
long ret;
|
|
|
|
ret = __infer_nondet_long_int();
|
|
INFER_EXCLUDE_CONDITION(ret < 0);
|
|
return ret;
|
|
}
|
|
|
|
// requires stream to be allocated
|
|
int putc(int c, FILE* stream) {
|
|
int rand;
|
|
FILE tmp;
|
|
|
|
tmp = *stream;
|
|
rand = __infer_nondet_int();
|
|
if (rand > 0)
|
|
return c; // success
|
|
else
|
|
return EOF; // failure
|
|
}
|
|
|
|
int access(const char* path, int mode) {
|
|
int success;
|
|
|
|
// force path to be allocated
|
|
__require_allocated_array(path);
|
|
|
|
// determine return value
|
|
success = __infer_nondet_int();
|
|
|
|
return (success > 0) ? 0 : -1;
|
|
}
|
|
|
|
size_t confstr(int name, char* buf, size_t len) {
|
|
int ret;
|
|
|
|
// determine return value
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < 0);
|
|
|
|
// buf should be allocated if len is not zero. Otherwise, we want buf=0.
|
|
if (len)
|
|
__require_allocated_array(buf);
|
|
else
|
|
INFER_EXCLUDE_CONDITION(buf != 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// return a non-deterministic value
|
|
// stream is not required to be allocated
|
|
int fflush(FILE* stream) { return __infer_nondet_int(); }
|
|
|
|
int flock(int fd, int operation) {
|
|
int ret;
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int fsync(int fildes) {
|
|
int ret;
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int fsctl(const char* path,
|
|
unsigned long request,
|
|
void* data,
|
|
unsigned int options) {
|
|
int ret;
|
|
|
|
// forces path and data to be allocated
|
|
__require_allocated_array(path);
|
|
__require_allocated_array(data);
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int getrusage(int who, struct rusage* r_usage) {
|
|
int ret;
|
|
|
|
INFER_EXCLUDE_CONDITION(r_usage == 0);
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
#define gettimeofday_tzp_decl void* __restrict tzp
|
|
#else
|
|
#ifdef __CYGWIN__
|
|
#define gettimeofday_tzp_decl void* __restrict tzp
|
|
#else
|
|
#define gettimeofday_tzp_decl struct timezone* __restrict tzp
|
|
#endif
|
|
#endif
|
|
|
|
int gettimeofday(struct timeval* __restrict tp, gettimeofday_tzp_decl) {
|
|
struct timeval tmp_tp;
|
|
struct timezone tmp_tzp;
|
|
int success;
|
|
|
|
if (tp != 0)
|
|
*tp = tmp_tp;
|
|
if (tzp != 0)
|
|
*(struct timezone*)tzp = tmp_tzp;
|
|
|
|
success = __infer_nondet_int();
|
|
return success ? 0 : -1;
|
|
}
|
|
|
|
struct tm* localtime_r(const time_t* __restrict timer,
|
|
struct tm* __restrict result) {
|
|
int success;
|
|
struct tm tmp;
|
|
|
|
INFER_EXCLUDE_CONDITION(timer == 0);
|
|
INFER_EXCLUDE_CONDITION(result == 0);
|
|
|
|
success = __infer_nondet_int();
|
|
*result = tmp;
|
|
|
|
return (success > 0) ? result : 0;
|
|
}
|
|
|
|
int mkdir(const char* filename, mode_t mode) {
|
|
int ret;
|
|
|
|
__require_allocated_array(filename);
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int munmap(void* addr, size_t len) {
|
|
int ret;
|
|
|
|
INFER_EXCLUDE_CONDITION(addr == 0);
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutex_destroy(pthread_mutex_t* mutex) {
|
|
INFER_EXCLUDE_CONDITION(mutex == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutex_init(pthread_mutex_t* __restrict mutex,
|
|
const pthread_mutexattr_t* __restrict attr) {
|
|
INFER_EXCLUDE_CONDITION(mutex == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutex_lock(pthread_mutex_t* mutex) {
|
|
INFER_EXCLUDE_CONDITION(mutex == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutex_trylock(pthread_mutex_t* mutex) {
|
|
INFER_EXCLUDE_CONDITION(mutex == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutex_unlock(pthread_mutex_t* mutex) {
|
|
INFER_EXCLUDE_CONDITION(mutex == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr) {
|
|
INFER_EXCLUDE_CONDITION(attr == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutexattr_init(pthread_mutexattr_t* attr) {
|
|
INFER_EXCLUDE_CONDITION(attr == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value
|
|
int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) {
|
|
INFER_EXCLUDE_CONDITION(attr == 0);
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// returns a nondeterministc value and forces type to be allocated and set its
|
|
// content
|
|
int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type) {
|
|
INFER_EXCLUDE_CONDITION(attr == 0);
|
|
*type = __infer_nondet_int();
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// return a positive non-deterministic number or -1.
|
|
// requires stream to be allocated
|
|
int fileno(FILE* stream) {
|
|
int ret = __infer_nondet_int();
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret == 0);
|
|
return ret;
|
|
}
|
|
|
|
int fstat(int fildes, struct stat* buf) {
|
|
int ret;
|
|
struct stat s; // uninitialized struct stat
|
|
*buf = s;
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
return ret;
|
|
}
|
|
|
|
// treates as skyp. Return nondeterministically 0 or -1
|
|
int futimes(int fildes, const struct timeval times[2]) {
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef getchar // cygwin defines getchar as a macro
|
|
#undef getchar
|
|
#endif
|
|
int getchar(void) {
|
|
// randomly produce an error
|
|
int ret = __infer_nondet_int();
|
|
if (ret < 0)
|
|
return EOF;
|
|
else
|
|
return ret;
|
|
}
|
|
|
|
int isatty(int fildes) {
|
|
int ret;
|
|
|
|
ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < 0 || ret > 1);
|
|
return ret;
|
|
}
|
|
|
|
void perror(const char* s) {
|
|
__require_allocated_array(s);
|
|
}
|
|
|
|
int pipe(int fildes[2]) {
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
return ret;
|
|
}
|
|
|
|
int raise(int sig) { return __infer_nondet_int(); }
|
|
|
|
ssize_t read(int fildes, void* buf, size_t nbyte) {
|
|
if (nbyte == 0)
|
|
return 0;
|
|
__require_allocated_array(buf);
|
|
INFER_EXCLUDE_CONDITION(__get_array_length(buf) < nbyte);
|
|
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > nbyte);
|
|
return ret;
|
|
}
|
|
|
|
int sigaction(int sig, const struct sigaction* act, struct sigaction* oact) {
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || ret > 0);
|
|
return ret;
|
|
}
|
|
|
|
// return the first argument
|
|
// long __builtin_expect(long x, long y) {
|
|
// return x;
|
|
//}
|
|
// TODO: this function has been disabled because it cannot be compiled with
|
|
// LLVM.
|
|
// It is normally a builtin that should not be implemented and LLVM complains
|
|
// about this
|
|
|
|
#ifdef clearerr // cygwin defines clearerr as a macro
|
|
#undef clearerr
|
|
#endif
|
|
// modelled as skip
|
|
// stream is required to be allocated
|
|
void clearerr(FILE* stream) {
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
}
|
|
|
|
#ifdef ferror // cygwin defines ferror as a macro
|
|
#undef ferror
|
|
#endif
|
|
// return a nondeterministic value
|
|
// stream required to be allocated
|
|
int ferror(FILE* stream) {
|
|
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
#ifdef feof // cygwin defines feof as a macro
|
|
#undef feof
|
|
#endif
|
|
// return a nondeterministic value
|
|
// stream required to be allocated
|
|
int feof(FILE* stream) {
|
|
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// write to *pos and return either 0 or -1
|
|
// stream is required to be allocated
|
|
int fgetpos(FILE* __restrict stream, fpos_t* __restrict pos) {
|
|
|
|
int success;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
#ifdef __APPLE__ // fpos_t is a long in MacOS, but a struct in Linux.
|
|
*pos = __infer_nondet_long_int();
|
|
#else
|
|
pos->__pos = __infer_nondet_long_int();
|
|
#endif
|
|
success = __infer_nondet_int();
|
|
if (success)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// read from *pos and return either 0 or -1
|
|
// stream is required to be allocated
|
|
int fsetpos(FILE* stream, const fpos_t* pos) {
|
|
|
|
int success;
|
|
FILE tmp;
|
|
tmp = *stream;
|
|
fpos_t t;
|
|
t = *pos;
|
|
success = __infer_nondet_int();
|
|
if (success)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// return a value between 0 and nmemb
|
|
size_t fread(void* __restrict ptr,
|
|
size_t size,
|
|
size_t nmemb,
|
|
FILE* __restrict stream) {
|
|
size_t res;
|
|
res = __infer_nondet_size_t();
|
|
if (size == 0 || nmemb == 0)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(res < 0 || res > nmemb);
|
|
return res;
|
|
}
|
|
|
|
// return a value between 0 and nmemb
|
|
size_t fwrite(const void* __restrict ptr,
|
|
size_t size,
|
|
size_t nmemb,
|
|
FILE* __restrict stream) {
|
|
size_t res;
|
|
res = __infer_nondet_size_t();
|
|
if (size == 0 || nmemb == 0)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(res < 0 || res > nmemb);
|
|
return res;
|
|
}
|
|
|
|
size_t strcspn(const char* s1, const char* s2) {
|
|
__require_allocated_array(s1);
|
|
__require_allocated_array(s2);
|
|
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < 0);
|
|
return ret;
|
|
}
|
|
|
|
// There is non-standard version of strerr_r:
|
|
// http://linux.die.net/man/3/strerror_r
|
|
// It's not modelled right now
|
|
#if defined __APPLE__ || (defined __USE_XOPEN2K && !defined __USE_GNU)
|
|
int strerror_r(int errnum, char* strerrbuf, size_t buflen) {
|
|
__require_allocated_array(strerrbuf);
|
|
INFER_EXCLUDE_CONDITION(__get_array_length(strerrbuf) < buflen);
|
|
|
|
return __infer_nondet_int();
|
|
}
|
|
#endif
|
|
|
|
ssize_t write(int fildes, const void* buf, size_t nbyte) {
|
|
__require_allocated_array(buf);
|
|
INFER_EXCLUDE_CONDITION(__get_array_length(buf) < nbyte);
|
|
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || nbyte < ret);
|
|
return ret;
|
|
}
|
|
|
|
int creat(const char* path, mode_t mode) {
|
|
__require_allocated_array(path);
|
|
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1);
|
|
return ret;
|
|
}
|
|
|
|
// modeled as skip
|
|
int fcntl(int fildes, int cmd, ...) {
|
|
int ret = __infer_nondet_int();
|
|
return ret;
|
|
}
|
|
|
|
// modelled as skip
|
|
int sigprocmask(int how, const sigset_t* set, sigset_t* oset) {
|
|
int ret = __infer_nondet_int();
|
|
INFER_EXCLUDE_CONDITION(ret < -1 || 0 < ret);
|
|
return ret;
|
|
}
|
|
|
|
// modelled as skip
|
|
void setbuf(FILE* __restrict stream, char* __restrict buf) {}
|
|
|
|
// return nondeterministically 0 or EOF
|
|
int setvbuf(FILE* __restrict stream,
|
|
char* __restrict buf,
|
|
int mode,
|
|
size_t size) {
|
|
int n;
|
|
|
|
n = __infer_nondet_int();
|
|
if (n)
|
|
return 0;
|
|
else
|
|
return EOF;
|
|
}
|
|
|
|
// the array base must be allocated with at least nmemb elements
|
|
// nondeterministically return 0 or a pointer inside the array
|
|
void* bsearch(const void* key,
|
|
const void* base,
|
|
size_t nmemb,
|
|
size_t size,
|
|
int (*compar)(const void*, const void*)) {
|
|
int base_size;
|
|
int nondet;
|
|
int offset;
|
|
nondet = __infer_nondet_int();
|
|
offset = __infer_nondet_int();
|
|
__require_allocated_array(base);
|
|
base_size = __get_array_length(base);
|
|
INFER_EXCLUDE_CONDITION(nmemb > base_size);
|
|
if (nondet)
|
|
return 0;
|
|
INFER_EXCLUDE_CONDITION(offset < 0 || offset >= nmemb);
|
|
return (char*)base + offset;
|
|
}
|
|
|
|
// return a nondeterministic value
|
|
int mblen(const char* s, size_t n) { return __infer_nondet_int(); }
|
|
|
|
// return a nondeterministic value
|
|
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n) {
|
|
return (size_t)__infer_nondet_int();
|
|
}
|
|
|
|
// return a nondeterministic value
|
|
int mbtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n) {
|
|
return __infer_nondet_int();
|
|
}
|
|
|
|
// modeled as skip
|
|
void qsort(void* base,
|
|
size_t nmemb,
|
|
size_t size,
|
|
int (*compar)(const void*, const void*)) {}
|
|
|
|
// return a nondeterministic value
|
|
int strcoll(const char* s1, const char* s2) { return __infer_nondet_int(); }
|
|
|
|
// return a nondeterministic value
|
|
size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n) {
|
|
return (size_t)__infer_nondet_int();
|
|
}
|
|
|
|
// return a nondeterministic value
|
|
int wctomb(char* s, wchar_t wc) { return __infer_nondet_int(); }
|
|
|
|
// modeled like open
|
|
int socket(int namespace_, int style, int protocol) {
|
|
int* ret = (int*)malloc(sizeof(int));
|
|
if (ret) {
|
|
__set_file_attribute(ret);
|
|
INFER_EXCLUDE_CONDITION(ret < (int*)1); // force result to be > 0
|
|
return (size_t)ret;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void* xcalloc(size_t nmemb, size_t size) {
|
|
void* ret = calloc(nmemb, size);
|
|
INFER_EXCLUDE_CONDITION(ret == NULL);
|
|
return ret;
|
|
}
|
|
|
|
void* xmalloc(size_t size) {
|
|
void* ret = malloc(size);
|
|
INFER_EXCLUDE_CONDITION(ret == NULL);
|
|
return ret;
|
|
}
|