Skip to content

Commit df81a9c

Browse files
author
Daniel Kroening
authored
Merge pull request #1167 from tautschnig/c-library-ext
C library modelling: fgets, getopt, vasprintf
2 parents ea476f7 + f691135 commit df81a9c

File tree

4 files changed

+186
-10
lines changed

4 files changed

+186
-10
lines changed

regression/cbmc/fgets1/main.c

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <stdio.h>
2+
#include <assert.h>
3+
4+
int main()
5+
{
6+
char buffer[3]={'a', 'b', '\0'};
7+
FILE *f=fdopen(0, "r");
8+
if(!f)
9+
return 1;
10+
11+
char *p=fgets(buffer, 3, f);
12+
if(p)
13+
{
14+
assert(buffer[1]==p[1]);
15+
assert(buffer[2]=='\0');
16+
assert(p[1]=='b'); // expected to fail
17+
}
18+
19+
fclose(f);
20+
21+
return 0;
22+
}

regression/cbmc/fgets1/test.desc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
\[main.assertion.3\] assertion p\[1\]=='b': FAILURE
8+
\*\* 1 of 38 failed \(2 iterations\)
9+
--
10+
^warning: ignoring

src/ansi-c/library/getopt.c

+54-9
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,67 @@
33
extern char *optarg;
44
extern int optind;
55

6+
#ifndef __CPROVER_STRING_H_INCLUDED
7+
#include <string.h>
8+
#define __CPROVER_STRING_H_INCLUDED
9+
#endif
10+
611
inline int getopt(int argc, char * const argv[],
712
const char *optstring)
813
{
914
__CPROVER_HIDE:;
10-
int result_index;
11-
__CPROVER_assume(result_index>=0);
12-
(void)*optstring;
13-
if(optind>=argc)
15+
int result=-1;
16+
17+
if(optind==0)
18+
optind=1;
19+
20+
if(optind>=argc || argv[optind][0]!='-')
1421
return -1;
15-
__CPROVER_assume(result_index<argc && result_index>=optind);
22+
23+
size_t result_index;
24+
__CPROVER_assume(
25+
result_index<strlen(optstring) && optstring[result_index]!=':');
1626
#ifdef __CPROVER_STRING_ABSTRACTION
1727
__CPROVER_assert(__CPROVER_is_zero_string(optstring),
1828
"getopt zero-termination of 3rd argument");
1929
#endif
20-
optarg = argv[result_index];
21-
optind = result_index+1;
22-
int retval;
23-
return retval;
30+
31+
_Bool found;
32+
if(found)
33+
{
34+
result=optstring[result_index];
35+
if(skipped)
36+
++optind;
37+
}
38+
39+
if(result!=-1 && optind<argc && optstring[result_index+1]==':')
40+
{
41+
_Bool has_no_arg;
42+
if(has_no_arg)
43+
{
44+
optarg=argv[optind];
45+
++optind;
46+
}
47+
else
48+
optarg=NULL;
49+
}
50+
51+
return result;
52+
}
53+
54+
/* FUNCTION: getopt_long */
55+
56+
int getopt(int argc, char * const argv[], const char *optstring);
57+
58+
inline int getopt_long(int argc, char * const argv[], const char *optstring,
59+
const struct option *longopts, int *longindex)
60+
{
61+
// trigger valid-pointer checks (if enabled), even though we don't
62+
// use the parameter in this model
63+
(void)*longopts;
64+
// avoid unused-parameter warnings when compiling using GCC (for
65+
// internal library syntax checks)
66+
(void)longindex;
67+
68+
return getopt(argc, argv, optstring);
2469
}

src/ansi-c/library/stdio.c

+100-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,14 @@ inline FILE *fopen(const char *filename, const char *mode)
6565
FILE *fopen_result;
6666

6767
_Bool fopen_error;
68+
69+
#if !defined(__linux__) || defined(__GLIBC__)
6870
fopen_result=fopen_error?NULL:malloc(sizeof(FILE));
71+
#else
72+
// libraries need to expose the definition of FILE; this is the
73+
// case for musl
74+
fopen_result=fopen_error?NULL:malloc(sizeof(int));
75+
#endif
6976

7077
#ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS
7178
__CPROVER_set_must(fopen_result, "open");
@@ -99,6 +106,11 @@ inline FILE* freopen(const char *filename, const char *mode, FILE *f)
99106
#define __CPROVER_STDIO_H_INCLUDED
100107
#endif
101108

109+
#ifndef __CPROVER_STDLIB_H_INCLUDED
110+
#include <stdlib.h>
111+
#define __CPROVER_STDLIB_H_INCLUDED
112+
#endif
113+
102114
inline int fclose(FILE *stream)
103115
{
104116
__CPROVER_HIDE:;
@@ -135,19 +147,56 @@ inline FILE *fdopen(int handle, const char *mode)
135147
"fdopen zero-termination of 2nd argument");
136148
#endif
137149

150+
#if !defined(__linux__) || defined(__GLIBC__)
138151
FILE *f=malloc(sizeof(FILE));
152+
#else
153+
// libraries need to expose the definition of FILE; this is the
154+
// case for musl
155+
FILE *f=malloc(sizeof(int));
156+
#endif
139157

140158
return f;
141159
}
142160

161+
/* FUNCTION: _fdopen */
162+
163+
// This is for Apple
164+
165+
#ifndef __CPROVER_STDIO_H_INCLUDED
166+
#include <stdio.h>
167+
#define __CPROVER_STDIO_H_INCLUDED
168+
#endif
169+
170+
#ifndef __CPROVER_STDLIB_H_INCLUDED
171+
#include <stdlib.h>
172+
#define __CPROVER_STDLIB_H_INCLUDED
173+
#endif
174+
175+
#ifdef __APPLE__
176+
inline FILE *_fdopen(int handle, const char *mode)
177+
{
178+
__CPROVER_HIDE:;
179+
(void)handle;
180+
(void)*mode;
181+
#ifdef __CPROVER_STRING_ABSTRACTION
182+
__CPROVER_assert(__CPROVER_is_zero_string(mode),
183+
"fdopen zero-termination of 2nd argument");
184+
#endif
185+
186+
FILE *f=malloc(sizeof(FILE));
187+
188+
return f;
189+
}
190+
#endif
191+
143192
/* FUNCTION: fgets */
144193

145194
#ifndef __CPROVER_STDIO_H_INCLUDED
146195
#include <stdio.h>
147196
#define __CPROVER_STDIO_H_INCLUDED
148197
#endif
149198

150-
inline char *fgets(char *str, int size, FILE *stream)
199+
char *fgets(char *str, int size, FILE *stream)
151200
{
152201
__CPROVER_HIDE:;
153202
__CPROVER_bool error;
@@ -169,6 +218,16 @@ inline char *fgets(char *str, int size, FILE *stream)
169218
__CPROVER_is_zero_string(str)=!error;
170219
__CPROVER_zero_string_length(str)=resulting_size;
171220
}
221+
#else
222+
if(size>0)
223+
{
224+
int str_length;
225+
__CPROVER_assume(str_length>=0 && str_length<size);
226+
char contents_nondet[str_length];
227+
__CPROVER_array_replace(str, contents_nondet);
228+
if(!error)
229+
str[str_length]='\0';
230+
}
172231
#endif
173232

174233
return error?0:str;
@@ -735,3 +794,43 @@ inline int vfprintf(FILE *stream, const char *restrict format, va_list arg)
735794

736795
return result;
737796
}
797+
798+
/* FUNCTION: vasprintf */
799+
800+
#ifndef __CPROVER_STDIO_H_INCLUDED
801+
#include <stdio.h>
802+
#define __CPROVER_STDIO_H_INCLUDED
803+
#endif
804+
805+
#ifndef __CPROVER_STDARG_H_INCLUDED
806+
#include <stdarg.h>
807+
#define __CPROVER_STDARG_H_INCLUDED
808+
#endif
809+
810+
#ifndef __CPROVER_STDLIB_H_INCLUDED
811+
#include <stdlib.h>
812+
#define __CPROVER_STDLIB_H_INCLUDED
813+
#endif
814+
815+
inline int vasprintf(char **ptr, const char *fmt, va_list ap)
816+
{
817+
(void)*fmt;
818+
(void)ap;
819+
820+
int result_buffer_size;
821+
if(result_buffer_size<=0)
822+
return -1;
823+
824+
*ptr=malloc(result_buffer_size);
825+
for(int i=0; i<result_buffer_size; ++i)
826+
{
827+
char c;
828+
(*ptr)[i]=c;
829+
if(c=='\0')
830+
break;
831+
}
832+
833+
__CPROVER_assume(i<result_buffer_size);
834+
835+
return i;
836+
}

0 commit comments

Comments
 (0)