diff --git a/share/libc/stdio.h b/share/libc/stdio.h index 9c27119c016ce7fced52dde77b279b8f1db2630b..d9531f816937a82d5727cb2327b7d56e19708fd7 100644 --- a/share/libc/stdio.h +++ b/share/libc/stdio.h @@ -222,9 +222,13 @@ extern int fgetc(FILE *stream); /*@ requires valid_stream: \valid(stream); - assigns s[0..size] \from indirect:size, indirect:*stream; + requires room_s: \valid(s+(0..size-1)); + assigns s[0..size-1] \from indirect:size, indirect:*stream; assigns \result \from s, indirect:size, indirect:*stream; ensures result_null_or_same: \result == \null || \result == s; + ensures initialization:at_least_one:\result != \null ==> \initialized(&s[0]); + // the return value does not tell how many characters were written, + // so we can only ensure the first one was initialized ensures terminated_string_on_success: \result != \null ==> valid_string(s); */ @@ -244,14 +248,26 @@ extern int getc(FILE *stream); /*@ assigns \result \from *__fc_stdin ; */ extern int getchar(void); +// Number of characters that will read by gets() /*@ - assigns s[..] \from *__fc_stdin ; - assigns \result \from s, __fc_stdin; + axiomatic GetsLength { + logic size_t gets_length{L} reads *__fc_stdin; + } +*/ + +/*@ + requires room_s: \valid(s+(0..gets_length)); + assigns s[0..gets_length] \from *__fc_stdin ; + assigns \result \from s, *__fc_stdin; + assigns *__fc_stdin \from *__fc_stdin; ensures result_null_or_same: \result == s || \result == \null; */ extern char *gets(char *s); -/*@ assigns *stream \from c; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from c; +*/ extern int putc(int c, FILE *stream); /*@ assigns *__fc_stdout \from c; */ @@ -260,7 +276,10 @@ extern int putchar(int c); /*@ assigns *__fc_stdout \from s[..]; */ extern int puts(const char *s); -/*@ assigns *stream \from c; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from c; +*/ extern int ungetc(int c, FILE *stream); /*@ @@ -311,50 +330,101 @@ extern int fsetpos(FILE *stream, const fpos_t *pos); */ extern long int ftell(FILE *stream); -/*@ assigns *stream \from \nothing; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from \nothing; + */ extern void rewind(FILE *stream); -/*@ assigns *stream \from \nothing; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from \nothing; + */ extern void clearerr(FILE *stream); -/*@ assigns \result \from *stream ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int feof(FILE *stream); -/*@ assigns \result \from *stream ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int fileno(FILE *stream); -/*@ assigns *stream \from \nothing ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from \nothing; +*/ extern void flockfile(FILE *stream); -/*@ assigns *stream \from \nothing ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from \nothing; +*/ extern void funlockfile(FILE *stream); -/*@ assigns \result,*stream \from \nothing ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns \result,*stream \from \nothing; +*/ extern int ftrylockfile(FILE *stream); -/*@ assigns \result \from *stream ;*/ +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int ferror(FILE *stream); -/*@ assigns __fc_stdout \from __fc_errno, s[..]; */ +/*@ + requires valid_string_s: valid_read_string(s); + assigns __fc_stdout \from __fc_errno, s[..]; + */ extern void perror(const char *s); -/*@ assigns \result,*stream \from *stream; */ +/*@ + requires valid_stream: \valid(stream); + assigns \result,*stream \from *stream; +*/ extern int getc_unlocked(FILE *stream); /*@ assigns \result \from *__fc_stdin ; */ extern int getchar_unlocked(void); -/*@ assigns *stream \from c; */ + +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from c; +*/ extern int putc_unlocked(int c, FILE *stream); + /*@ assigns *__fc_stdout \from c; */ extern int putchar_unlocked(int c); -/*@ assigns *stream \from \nothing; */ +/*@ + requires valid_stream: \valid(stream); + assigns *stream \from \nothing; +*/ extern void clearerr_unlocked(FILE *stream); -/*@ assigns \result \from *stream ;*/ + +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int feof_unlocked(FILE *stream); -/*@ assigns \result \from *stream ;*/ + +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int ferror_unlocked(FILE *stream); -/*@ assigns \result \from *stream ;*/ + +/*@ + requires valid_stream: \valid(stream); + assigns \result \from *stream; +*/ extern int fileno_unlocked(FILE *stream); + extern int fflush_unlocked(FILE *stream); extern int fgetc_unlocked(FILE *stream); extern int fputc_unlocked(int c, FILE *stream); diff --git a/tests/libc/stdio_h.c b/tests/libc/stdio_h.c index 9e9ac6ba242de5f7bb922d965b18eed6b3393c80..a1d6f3fa161b6d6edc7ac04fd41056285eea2f00 100644 --- a/tests/libc/stdio_h.c +++ b/tests/libc/stdio_h.c @@ -29,5 +29,15 @@ int main() { if (!redirected) return 3; printf("redirected to file"); fclose(redirected); + + char fgets_buf0[1]; + char *fgets_res = fgets(fgets_buf0, 1, f); // ok + if (!fgets_res) return 1; + //@ check \initialized(&fgets_buf0[0]); + if (nondet) { + fgets(fgets_buf0, 2, f); // error: buf too small + //@ assert unreachable: \false; + } + return 0; }