Skip to content

Commit 81567a1

Browse files
committed
C library: Refine and improve stdio models
Fixes portability to FreeBSD, which redefines several functions as macros that would only conditionally call that function. Also, ensure that stdin/stdout/stderr point to valid objects when those are fdopen'ed.
1 parent daace74 commit 81567a1

File tree

2 files changed

+126
-24
lines changed

2 files changed

+126
-24
lines changed

regression/cbmc-library/fileno-01/main.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@
33

44
int main()
55
{
6-
// requires initialization of stdin/stdout/stderr
7-
// assert(fileno(stdin) == 0);
8-
// assert(fileno(stdout) == 1);
9-
// assert(fileno(stderr) == 2);
10-
116
int fd;
127
FILE *some_file = fdopen(fd, "");
13-
assert(fileno(some_file) >= -1);
8+
if(some_file)
9+
assert(fileno(some_file) >= -1);
1410

1511
return 0;
1612
}

src/ansi-c/library/stdio.c

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,7 @@
66
#define __CPROVER_STDIO_H_INCLUDED
77
#endif
88

9-
/* undefine macros in OpenBSD's stdio.h that are problematic to the checker. */
10-
#if defined(__OpenBSD__)
11-
#undef getchar
129
#undef putchar
13-
#undef getc
14-
#undef feof
15-
#undef ferror
16-
#undef fileno
17-
#endif
1810

1911
__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(void);
2012

@@ -213,25 +205,80 @@ __CPROVER_HIDE:;
213205
#define __CPROVER_STDLIB_H_INCLUDED
214206
#endif
215207

208+
#ifndef __CPROVER_ERRNO_H_INCLUDED
209+
# include <errno.h>
210+
# define __CPROVER_ERRNO_H_INCLUDED
211+
#endif
212+
213+
#ifndef _WIN32
214+
FILE *stdin;
215+
FILE *stdout;
216+
FILE *stderr;
217+
#endif
218+
216219
FILE *fdopen(int handle, const char *mode)
217220
{
218221
__CPROVER_HIDE:;
219-
(void)handle;
222+
if(handle < 0)
223+
{
224+
errno = EBADF;
225+
return NULL;
226+
}
220227
(void)*mode;
221228
#ifdef __CPROVER_STRING_ABSTRACTION
222229
__CPROVER_assert(__CPROVER_is_zero_string(mode),
223230
"fdopen zero-termination of 2nd argument");
224231
#endif
225232

226-
#if !defined(__linux__) || defined(__GLIBC__)
233+
#ifndef _WIN32
234+
FILE **f_alias = NULL;
235+
switch(handle)
236+
{
237+
case 0:
238+
f_alias = &stdin;
239+
break;
240+
case 1:
241+
f_alias = &stdout;
242+
break;
243+
case 2:
244+
f_alias = &stderr;
245+
break;
246+
}
247+
248+
if(f_alias != NULL && *f_alias != NULL)
249+
{
250+
__CPROVER_assume(fileno(*f_alias) == handle);
251+
return *f_alias;
252+
}
253+
# if !defined(__linux__) || defined(__GLIBC__)
227254
FILE *f=malloc(sizeof(FILE));
228255
#else
229-
// libraries need to expose the definition of FILE; this is the
256+
// libraries need not expose the definition of FILE; this is the
230257
// case for musl
231258
FILE *f=malloc(sizeof(int));
232259
#endif
260+
if(f_alias != NULL)
261+
*f_alias = f;
262+
__CPROVER_assume(fileno(f) == handle);
233263

234264
return f;
265+
#else
266+
switch(handle)
267+
{
268+
case 0:
269+
return stdin;
270+
case 1:
271+
return stdout;
272+
case 2:
273+
return stderr;
274+
default:
275+
{
276+
FILE *f = malloc(sizeof(FILE));
277+
__CPROVER_assume(fileno(f) == handle);
278+
return f;
279+
}
280+
}
281+
#endif
235282
}
236283

237284
/* FUNCTION: _fdopen */
@@ -251,18 +298,56 @@ FILE *fdopen(int handle, const char *mode)
251298
#define __CPROVER_STDLIB_H_INCLUDED
252299
#endif
253300

301+
#ifndef __CPROVER_ERRNO_H_INCLUDED
302+
# include <errno.h>
303+
# define __CPROVER_ERRNO_H_INCLUDED
304+
#endif
305+
254306
#ifdef __APPLE__
307+
308+
# ifndef LIBRARY_CHECK
309+
FILE *stdin;
310+
FILE *stdout;
311+
FILE *stderr;
312+
# endif
313+
255314
FILE *_fdopen(int handle, const char *mode)
256315
{
257316
__CPROVER_HIDE:;
258-
(void)handle;
317+
if(handle < 0)
318+
{
319+
errno = EBADF;
320+
return NULL;
321+
}
259322
(void)*mode;
260323
#ifdef __CPROVER_STRING_ABSTRACTION
261324
__CPROVER_assert(__CPROVER_is_zero_string(mode),
262325
"fdopen zero-termination of 2nd argument");
263326
#endif
264327

328+
FILE **f_alias = NULL;
329+
switch(handle)
330+
{
331+
case 0:
332+
f_alias = &stdin;
333+
break;
334+
case 1:
335+
f_alias = &stdout;
336+
break;
337+
case 2:
338+
f_alias = &stderr;
339+
break;
340+
}
341+
342+
if(f_alias != NULL && *f_alias != NULL)
343+
{
344+
__CPROVER_assume(fileno(*f_alias) == handle);
345+
return *f_alias;
346+
}
265347
FILE *f=malloc(sizeof(FILE));
348+
if(f_alias != NULL)
349+
*f_alias = f;
350+
__CPROVER_assume(fileno(f) == handle);
266351

267352
return f;
268353
}
@@ -466,6 +551,8 @@ __CPROVER_HIDE:;
466551
#define __CPROVER_STDIO_H_INCLUDED
467552
#endif
468553

554+
#undef feof
555+
469556
int __VERIFIER_nondet_int(void);
470557

471558
int feof(FILE *stream)
@@ -498,6 +585,8 @@ int feof(FILE *stream)
498585
#define __CPROVER_STDIO_H_INCLUDED
499586
#endif
500587

588+
#undef ferror
589+
501590
int __VERIFIER_nondet_int(void);
502591

503592
int ferror(FILE *stream)
@@ -530,6 +619,8 @@ int ferror(FILE *stream)
530619
#define __CPROVER_STDIO_H_INCLUDED
531620
#endif
532621

622+
#undef fileno
623+
533624
int __VERIFIER_nondet_int(void);
534625

535626
int fileno(FILE *stream)
@@ -695,6 +786,8 @@ int fgetc(FILE *stream)
695786
#define __CPROVER_STDIO_H_INCLUDED
696787
#endif
697788

789+
#undef getc
790+
698791
int __VERIFIER_nondet_int(void);
699792

700793
int getc(FILE *stream)
@@ -731,6 +824,8 @@ int getc(FILE *stream)
731824
#define __CPROVER_STDIO_H_INCLUDED
732825
#endif
733826

827+
#undef getchar
828+
734829
int __VERIFIER_nondet_int(void);
735830

736831
int getchar(void)
@@ -1593,20 +1688,31 @@ int vasprintf(char **ptr, const char *fmt, va_list ap)
15931688
# define __CPROVER_STDIO_H_INCLUDED
15941689
# endif
15951690

1691+
# ifndef __CPROVER_STDLIB_H_INCLUDED
1692+
# include <stdlib.h>
1693+
# define __CPROVER_STDLIB_H_INCLUDED
1694+
# endif
1695+
15961696
FILE *__acrt_iob_func(unsigned fd)
15971697
{
1598-
static FILE stdin_file;
1599-
static FILE stdout_file;
1600-
static FILE stderr_file;
1698+
static FILE *stdin_file;
1699+
static FILE *stdout_file;
1700+
static FILE *stderr_file;
16011701

16021702
switch(fd)
16031703
{
16041704
case 0:
1605-
return &stdin_file;
1705+
if(!stdin_file)
1706+
stdin_file = malloc(sizeof(FILE));
1707+
return stdin_file;
16061708
case 1:
1607-
return &stdout_file;
1709+
if(!stdout_file)
1710+
stdout_file = malloc(sizeof(FILE));
1711+
return stdout_file;
16081712
case 2:
1609-
return &stderr_file;
1713+
if(!stderr_file)
1714+
stderr_file = malloc(sizeof(FILE));
1715+
return stderr_file;
16101716
default:
16111717
return (FILE *)0;
16121718
}

0 commit comments

Comments
 (0)