From fd699101332a158f2983bee56042b736252c0eb2 Mon Sep 17 00:00:00 2001 From: Andre Maroneze <andre.oliveiramaroneze@cea.fr> Date: Thu, 22 Aug 2019 18:11:49 +0200 Subject: [PATCH] [Libc] fix/improve several specs in stdio.h --- share/libc/__fc_machdep.h | 20 +++ share/libc/stdio.h | 150 ++++++++++++++---- .../misc/custom_machdep/__fc_machdep_custom.h | 2 + 3 files changed, 137 insertions(+), 35 deletions(-) diff --git a/share/libc/__fc_machdep.h b/share/libc/__fc_machdep.h index f6f2d7e9a6d..55db3e0093e 100644 --- a/share/libc/__fc_machdep.h +++ b/share/libc/__fc_machdep.h @@ -99,6 +99,10 @@ /* POSIX */ #define __SSIZE_T int #define __SSIZE_MAX __FC_INT_MAX +/* stdio.h */ +#ifndef __FC_L_tmpnam +#define __FC_L_tmpnam 1024 +#endif /* stdint.h */ #define __FC_PTRDIFF_MIN __FC_INT_MIN #define __FC_PTRDIFF_MAX __FC_INT_MAX @@ -195,6 +199,10 @@ /* POSIX */ #define __SSIZE_T signed long #define __SSIZE_MAX __FC_LONG_MAX +/* stdio.h */ +#ifndef __FC_L_tmpnam +#define __FC_L_tmpnam 1024 +#endif /* stdint.h */ #define __FC_PTRDIFF_MIN __FC_LONG_MIN #define __FC_PTRDIFF_MAX __FC_LONG_MAX @@ -293,6 +301,10 @@ /* POSIX */ #define __SSIZE_T signed long #define __SSIZE_MAX __FC_LONG_MAX +/* stdio.h */ +#ifndef __FC_L_tmpnam +#define __FC_L_tmpnam 1024 +#endif /* stdint.h */ #define __FC_PTRDIFF_MIN __FC_LONG_MIN #define __FC_PTRDIFF_MAX __FC_LONG_MAX @@ -388,6 +400,10 @@ /* POSIX */ #define __SSIZE_T int #define __SSIZE_MAX __FC_INT_MAX +/* stdio.h */ +#ifndef __FC_L_tmpnam +#define __FC_L_tmpnam 1024 +#endif /* stdint.h */ #define __FC_PTRDIFF_MIN __FC_INT_MIN #define __FC_PTRDIFF_MAX __FC_INT_MAX @@ -558,6 +574,10 @@ /* POSIX */ #define __SSIZE_T signed long long +/* stdio.h */ +#ifndef __FC_L_tmpnam +#define __FC_L_tmpnam 20 +#endif /* stdint.h */ #define __FC_WCHAR_MIN 0 #define __FC_WCHAR_MAX __FC_USHRT_MAX diff --git a/share/libc/stdio.h b/share/libc/stdio.h index d9531f81693..7d8bec1bebe 100644 --- a/share/libc/stdio.h +++ b/share/libc/stdio.h @@ -44,6 +44,9 @@ __PUSH_FC_STDLIB #define BUFSIZ __FC_BUFSIZ #define FOPEN_MAX __FC_FOPEN_MAX #define FILENAME_MAX __FC_FILENAME_MAX +#ifndef __FC_L_tmpnam +#error machdep should have defined __FC_L_tmpnam! +#endif #define L_tmpnam __FC_L_tmpnam #include "__fc_define_seek_macros.h" @@ -67,10 +70,22 @@ extern FILE * __fc_stdout; non-interferent between them. */ -/*@ assigns \nothing; */ +/*@ // missing: assigns 'filesystem' \from filename[0..]; + // missing: assigns errno one of several possible values + requires valid_filename: valid_read_string(filename); + assigns \result \from indirect:filename[0..strlen(filename)]; + ensures result_ok_or_error: \result == 0 || \result == -1; +*/ extern int remove(const char *filename); -/*@ assigns \nothing; */ +/*@ // missing: assigns 'filesystem' \from old_name[0..], new_name[0..]; + // missing: assigns errno one of 21 different possible values + requires valid_old_name: valid_read_string(old_name); + requires valid_new_name: valid_read_string(new_name); + assigns \result \from indirect:old_name[0..strlen(old_name)], + indirect:new_name[0..strlen(new_name)]; + ensures result_ok_or_error: \result == 0 || \result == -1; +*/ extern int rename(const char *old_name, const char *new_name); FILE __fc_fopen[__FC_FOPEN_MAX]; @@ -83,33 +98,57 @@ FILE* const __fc_p_fopen = __fc_fopen; */ extern FILE *tmpfile(void); +char __fc_tmpnam[L_tmpnam]; +char * const __fc_p_tmpnam = __fc_tmpnam; + /*@ - assigns \result \from s[..]; - assigns s[..] \from \nothing; - // TODO: more precise behaviors from ISO C 7.19.4.4 + // Note: the tmpnam example in POSIX uses an array of size L_tmpnam+1 + // missing: assigns __fc_p_tmpnam[0..L_tmpnam] \from 'PRNG and internal state' + requires valid_s_or_null: s == \null || \valid(s+(0 .. L_tmpnam)); + assigns __fc_p_tmpnam[0 .. L_tmpnam] \from __fc_p_tmpnam[0 .. L_tmpnam], + indirect:s; + assigns s[0 .. L_tmpnam] \from indirect:s, __fc_p_tmpnam[0 .. L_tmpnam]; + assigns \result \from s, __fc_p_tmpnam; + ensures result_string_or_null: \result == \null || \result == s || + \result == __fc_p_tmpnam; */ extern char *tmpnam(char *s); /*@ + // missing: assigns errno requires valid_stream: \valid(stream); - assigns \result \from stream, stream->__fc_FILE_id; + assigns \result \from indirect:*stream; ensures result_zero_or_EOF: \result == 0 || \result == EOF; - // TODO: more precise behaviors from ISO C 7.19.4.1 */ extern int fclose(FILE *stream); /*@ + // missing: assigns errno requires null_or_valid_stream: stream == \null || \valid_read(stream); - assigns \result \from stream, stream->__fc_FILE_id; ensures result_zero_or_EOF: \result == 0 || \result == EOF; - // TODO: more precise behaviors from ISO C 7.19.5.2 + assigns \result \from indirect:*stream; + assigns *stream, __fc_fopen[0 .. __FC_FOPEN_MAX-1] + \from indirect:stream, *stream, + __fc_fopen[0 .. __FC_FOPEN_MAX-1]; // may flush ALL open streams + behavior flush_all: + assumes all_streams: stream == \null; + assigns __fc_fopen[0 .. __FC_FOPEN_MAX-1] + \from __fc_fopen[0 .. __FC_FOPEN_MAX-1]; // flush ALL open streams + assigns \result \from indirect:__fc_fopen[0 .. __FC_FOPEN_MAX-1]; + behavior flush_stream: + assumes single_stream: stream != \null; + assigns *stream \from *stream; + assigns \result \from indirect:*stream; + complete behaviors; + disjoint behaviors; */ extern int fflush(FILE *stream); /*@ requires valid_filename: valid_read_string(filename); requires valid_mode: valid_read_string(mode); - assigns \result \from indirect:filename[..], indirect:mode[..], __fc_p_fopen; + assigns \result \from indirect:filename[0..strlen(filename)], + indirect:mode[0..strlen(mode)], __fc_p_fopen; ensures result_null_or_valid_fd: \result==\null || (\subset(\result,&__fc_fopen[0 .. __FC_FOPEN_MAX-1])) ; */ @@ -118,8 +157,9 @@ extern FILE *fopen(const char * restrict filename, /*@ requires valid_mode: valid_read_string(mode); - assigns \result, __fc_fopen[fd] \from indirect:fd, indirect:mode[0..], - indirect:__fc_fopen[fd], __fc_p_fopen; + assigns \result, __fc_fopen[fd] \from indirect:fd, + indirect:mode[0..strlen(mode)], + indirect:__fc_fopen[fd], __fc_p_fopen; ensures result_null_or_valid_fd: \result == \null || (\subset(\result,&__fc_fopen[0 .. __FC_FOPEN_MAX-1])) ; */ @@ -235,17 +275,30 @@ extern int fgetc(FILE *stream); extern char *fgets(char * restrict s, int size, FILE * restrict stream); -/*@ assigns *stream ; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from c, *stream; + assigns \result \from indirect:*stream; +*/ extern int fputc(int c, FILE *stream); -/*@ assigns *stream \from s[..]; */ +/*@ + requires valid_string_s: valid_read_string(s); + assigns *stream \from s[0..strlen(s)]; + assigns \result \from indirect:s[0..strlen(s)], indirect:*stream; +*/ extern int fputs(const char * restrict s, FILE * restrict stream); -/*@ assigns \result,*stream \from *stream; */ +/*@ + requires valid_stream: \valid(stream); + assigns \result, *stream \from *stream; +*/ extern int getc(FILE *stream); -/*@ assigns \result \from *__fc_stdin ; */ +/*@ + assigns \result, *__fc_stdin \from *__fc_stdin; +*/ extern int getchar(void); // Number of characters that will read by gets() @@ -267,29 +320,39 @@ extern char *gets(char *s); /*@ requires valid_stream: \valid(stream); assigns *stream \from c; + assigns \result \from indirect:*stream; */ extern int putc(int c, FILE *stream); -/*@ assigns *__fc_stdout \from c; */ +/*@ + assigns *__fc_stdout \from c; + assigns \result \from indirect:*__fc_stdout; +*/ extern int putchar(int c); -/*@ assigns *__fc_stdout \from s[..]; */ +/*@ + requires valid_string_s: valid_read_string(s); + assigns *__fc_stdout \from s[0..strlen(s)]; + assigns \result \from indirect:s[0..strlen(s)], indirect:*__fc_stdout; +*/ extern int puts(const char *s); /*@ requires valid_stream: \valid(stream); - assigns *stream \from c; + assigns *stream \from indirect:c; + assigns \result \from indirect:c, indirect:*stream; + ensures result_ok_or_error: \result == c || \result == EOF; */ extern int ungetc(int c, FILE *stream); /*@ requires valid_ptr_block: \valid(((char*)ptr)+(0..(nmemb*size)-1)); requires valid_stream: \valid(stream); - assigns *(((char*)ptr)+(0..(nmemb*size)-1)) \from size, nmemb, *stream; - assigns \result \from size, *stream; + assigns *(((char*)ptr)+(0..(nmemb*size)-1)) + \from indirect:size, indirect:nmemb, indirect:*stream; + assigns \result \from size, indirect:*stream; ensures size_read: \result <= nmemb; ensures initialization: \initialized(((char*)ptr)+(0..(\result*size)-1)); - //TODO: specify precise fields from struct FILE */ extern size_t fread(void * restrict ptr, size_t size, size_t nmemb, @@ -298,15 +361,20 @@ extern size_t fread(void * restrict ptr, /*@ requires valid_ptr_block: \valid_read(((char*)ptr)+(0..(nmemb*size)-1)); requires valid_stream: \valid(stream); - assigns *stream, \result \from *(((char*)ptr)+(0..(nmemb*size)-1)); + assigns *stream, \result \from indirect:*(((char*)ptr)+(0..(nmemb*size)-1)); ensures size_written: \result <= nmemb; - //TODO: specify precise fields from struct FILE */ extern size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream); -/*@ assigns *pos \from *stream ; */ +/*@ + requires valid_stream: \valid(stream); + requires valid_pos: \valid(pos); + requires initialization:pos: \initialized(pos); + assigns *pos \from indirect:*stream; + assigns \result \from indirect:*stream; + */ extern int fgetpos(FILE * restrict stream, fpos_t * restrict pos); @@ -319,7 +387,12 @@ extern int fgetpos(FILE * restrict stream, */ extern int fseek(FILE *stream, long int offset, int whence); -/*@ assigns *stream \from *pos; */ +/*@ + requires valid_stream: \valid(stream); + requires valid_pos: \valid_read(pos); + requires initialization:pos: \initialized(pos); + assigns *stream \from *pos; +*/ extern int fsetpos(FILE *stream, const fpos_t *pos); /*@ @@ -344,13 +417,13 @@ extern void clearerr(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int feof(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int fileno(FILE *stream); @@ -374,13 +447,13 @@ extern int ftrylockfile(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int ferror(FILE *stream); /*@ requires valid_string_s: valid_read_string(s); - assigns __fc_stdout \from __fc_errno, s[..]; + assigns __fc_stdout \from __fc_errno, s[0..strlen(s)]; */ extern void perror(const char *s); @@ -389,16 +462,23 @@ extern void perror(const char *s); assigns \result,*stream \from *stream; */ extern int getc_unlocked(FILE *stream); -/*@ assigns \result \from *__fc_stdin ; */ + +/*@ + assigns \result \from *__fc_stdin; + */ extern int getchar_unlocked(void); /*@ requires valid_stream: \valid(stream); assigns *stream \from c; + assigns \result \from indirect:*stream; */ extern int putc_unlocked(int c, FILE *stream); -/*@ assigns *__fc_stdout \from c; */ +/*@ + assigns *__fc_stdout \from c; + assigns \result \from indirect:*__fc_stdout; + */ extern int putchar_unlocked(int c); /*@ @@ -409,19 +489,19 @@ extern void clearerr_unlocked(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int feof_unlocked(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int ferror_unlocked(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns \result \from *stream; + assigns \result \from indirect:*stream; */ extern int fileno_unlocked(FILE *stream); diff --git a/tests/misc/custom_machdep/__fc_machdep_custom.h b/tests/misc/custom_machdep/__fc_machdep_custom.h index fff2b8698ab..27db3084033 100644 --- a/tests/misc/custom_machdep/__fc_machdep_custom.h +++ b/tests/misc/custom_machdep/__fc_machdep_custom.h @@ -74,6 +74,8 @@ /* POSIX */ #define __SSIZE_T int +/* stdio.h */ +#define __FC_L_tmpnam 1024 /* stdint.h */ #define __FC_PTRDIFF_MIN __FC_INT_MIN #define __FC_PTRDIFF_MAX __FC_INT_MAX -- GitLab