From 20987ae23168a64dd68e40caac890b5fee30b6f3 Mon Sep 17 00:00:00 2001 From: Andre Maroneze <andre.maroneze@cea.fr> Date: Mon, 25 Mar 2024 11:48:58 +0100 Subject: [PATCH] [Libc] several fixes and spec improvements --- share/libc/__fc_builtin.c | 7 ++++++- share/libc/argz.h | 8 ++++++++ share/libc/fenv.h | 2 +- share/libc/glob.c | 1 + share/libc/glob.h | 10 ++++++++-- share/libc/netdb.h | 7 ++++--- share/libc/stdatomic.c | 1 - share/libc/stdatomic.h | 6 ++++-- share/libc/stdio.c | 9 ++++++--- share/libc/stdio.h | 6 +++--- share/libc/stdlib.h | 14 +++++++------- share/libc/string.h | 4 ++-- share/libc/wchar.h | 5 +++-- 13 files changed, 53 insertions(+), 27 deletions(-) diff --git a/share/libc/__fc_builtin.c b/share/libc/__fc_builtin.c index 00963b7c188..40ac7db1413 100644 --- a/share/libc/__fc_builtin.c +++ b/share/libc/__fc_builtin.c @@ -247,7 +247,12 @@ wint_t Frama_C_wint_t_interval(wint_t min, wint_t max) return r; } -/*@ assigns \nothing; */ +/*@ + terminates \false; + assigns \nothing; + ensures never_terminates: \false; + exits always_exits: \true; + */ extern void __builtin_abort(void) __attribute__((noreturn)); // GCC builtin void Frama_C_abort(void) diff --git a/share/libc/argz.h b/share/libc/argz.h index 81afda0c725..b68450d44a1 100644 --- a/share/libc/argz.h +++ b/share/libc/argz.h @@ -43,12 +43,14 @@ __BEGIN_DECLS typedef int error_t; /*@ + allocates *argz; assigns (*argz)[0..], *len, \result \from argv[0..][0..]; */ extern error_t argz_create (char *const argv[], char **restrict argz, size_t *restrict len); /*@ + allocates *argz; assigns (*argz)[0..], *len, \result \from string[0..], sep, (*argz)[0..], *len; */ extern error_t argz_create_sep (const char *restrict string, @@ -66,6 +68,7 @@ extern void argz_extract (const char *restrict argz, size_t len, extern void argz_stringify (char *argz, size_t len, int sep); /*@ + allocates *argz; assigns (*argz)[0..], *argz_len \from (*argz)[0..], *argz_len, buf[0..], buf_len; assigns \result \from indirect:(*argz)[0..], indirect:*argz_len, @@ -76,6 +79,7 @@ extern error_t argz_append (char **restrict argz, const char *restrict buf, size_t buf_len); /*@ + allocates *argz; assigns (*argz)[0..], *argz_len, \result \from (*argz)[0..], *argz_len, str[0..]; */ @@ -84,6 +88,7 @@ extern error_t argz_add (char **restrict argz, const char *restrict str); /*@ + allocates *argz; assigns (*argz)[0..], *argz_len, \result \from string[0..], delim; */ extern error_t argz_add_sep (char **restrict argz, @@ -91,6 +96,7 @@ extern error_t argz_add_sep (char **restrict argz, const char *restrict string, int delim); /*@ + frees *argz; assigns (*argz)[0..], *argz_len \from (*argz)[0..], *argz_len, entry[0..]; */ extern void argz_delete (char **restrict argz, @@ -98,6 +104,7 @@ extern void argz_delete (char **restrict argz, char *restrict entry); /*@ + allocates *argz; assigns (*argz)[0..], *argz_len, \result \from (*argz)[0..], *argz_len, before, before[0..], entry[0..]; @@ -108,6 +115,7 @@ extern error_t argz_insert (char **restrict argz, const char *restrict entry); /*@ + allocates *argz; assigns (*argz)[0..], *argz_len, *replace_count, \result \from (*argz)[0..], *argz_len, str[0..], with[0..], *replace_count; diff --git a/share/libc/fenv.h b/share/libc/fenv.h index 2ddec71c27e..1315383cde0 100644 --- a/share/libc/fenv.h +++ b/share/libc/fenv.h @@ -108,7 +108,7 @@ extern int fegetexceptflag(fexcept_t *flagp, int excepts); extern int fegetround(void); /*@ - assigns *envp \from __fc_fenv_state; + assigns *envp, __fc_fenv_state \from __fc_fenv_state; assigns \result \from indirect:__fc_fenv_state; */ extern int feholdexcept(fenv_t *envp); diff --git a/share/libc/glob.c b/share/libc/glob.c index 70550765741..83b532b3f0f 100644 --- a/share/libc/glob.c +++ b/share/libc/glob.c @@ -74,6 +74,7 @@ int glob(const char *pattern, int flags, pglob->gl_pathv[reserve_offs + prev_len + i] = (char*)"glob result"; } pglob->gl_pathv[prev_len + reserve_offs + pglob->gl_pathc] = 0; // terminator + pglob->gl_flags = flags | (Frama_C_nondet(0, GLOB_MAGCHAR)); if (Frama_C_nondet(0, 1)) { // simulate "no error" return 0; } else { diff --git a/share/libc/glob.h b/share/libc/glob.h index 01655d11eef..4046f1efb02 100644 --- a/share/libc/glob.h +++ b/share/libc/glob.h @@ -69,14 +69,20 @@ typedef struct __fc_glob_t { } glob_t; /*@ - assigns \result, *pglob \from indirect:pattern[0 .. strlen(pattern)], - indirect:flags, indirect:errfunc; + allocates pglob->gl_pathv; + assigns *pglob \from indirect:pattern[0 .. strlen(pattern)], + flags, + indirect:errfunc; + assigns \result \from indirect:pattern[0 .. strlen(pattern)], + indirect:flags, + indirect:errfunc; */ extern int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob); /*@ + frees pglob->gl_pathv; assigns *pglob \from *pglob; */ extern void globfree(glob_t *pglob); diff --git a/share/libc/netdb.h b/share/libc/netdb.h index 412d06331a4..0b09f4b9d9c 100644 --- a/share/libc/netdb.h +++ b/share/libc/netdb.h @@ -123,8 +123,8 @@ extern void endnetent(void); extern void endprotoent(void); extern void endservent(void); /*@ requires addrinfo_valid: \valid(addrinfo); - assigns \nothing; frees addrinfo; + assigns \nothing; ensures allocation: \allocable(addrinfo); */ extern void freeaddrinfo(struct addrinfo * addrinfo); @@ -143,12 +143,12 @@ extern const char *gai_strerror(int errcode); requires hints_option: hints == \null || \valid_read(hints); requires valid_res: \valid(res); + allocates *res; + assigns *res \from indirect:nodename, indirect:servname, indirect:hints; assigns \result \from indirect:nodename, indirect:servname,indirect:hints; assigns errno \from indirect:nodename, indirect:servname, indirect:hints; - allocates *res; - behavior empty_request: assumes empty: nodename == \null && servname == \null; assigns \result \from indirect:nodename, indirect:servname; @@ -180,6 +180,7 @@ extern int getaddrinfo( extern struct hostent *gethostbyaddr(const void *, socklen_t, int); /*@ + allocates \result; assigns \result, *\result \from name[0 .. strlen(name)]; */ extern struct hostent *gethostbyname(const char *name); diff --git a/share/libc/stdatomic.c b/share/libc/stdatomic.c index 30c975051b9..28723c038b5 100644 --- a/share/libc/stdatomic.c +++ b/share/libc/stdatomic.c @@ -26,7 +26,6 @@ #include "string.h" __PUSH_FC_STDLIB -/*@ assigns \nothing; */ void __fc_atomic_init_marker(void *obj, unsigned long long value) {} void atomic_thread_fence(memory_order order) {} diff --git a/share/libc/stdatomic.h b/share/libc/stdatomic.h index 32ef8fafd80..f02aee8016e 100644 --- a/share/libc/stdatomic.h +++ b/share/libc/stdatomic.h @@ -101,6 +101,8 @@ typedef _Atomic uintmax_t atomic_uintmax_t; // NOTE: The stubs below serve only to help parsing succeed and do not // match expected concurrence semantics. +/*@ assigns \nothing; */ +void __fc_atomic_init_marker(void *obj, unsigned long long value); #define atomic_init(obj, value) \ do { __fc_atomic_init_marker(obj, value); *obj = value; } while (0) @@ -185,7 +187,7 @@ unsigned long long __fc_atomic_exchange_explicit(void *object, *((char*)expected+(0 .. obj_size-1)), desired, indirect:obj_size; assigns \result \from indirect:*((char*)object+(0 .. obj_size-1)), indirect:*((char*)expected+(0 .. obj_size-1)), - indirect:desired, indirect:obj_size; + indirect:obj_size; */ _Bool __fc_atomic_compare_exchange_strong(void *object, void *expected, unsigned long long desired, @@ -201,7 +203,7 @@ _Bool __fc_atomic_compare_exchange_strong(void *object, void *expected, desired, indirect:success, indirect:failure, indirect:obj_size; assigns \result \from indirect:*((char*)object+(0 .. obj_size-1)), indirect:*((char*)expected+(0 .. obj_size-1)), - indirect:desired, indirect:success, indirect:failure, + indirect:success, indirect:failure, indirect:obj_size; */ _Bool __fc_atomic_compare_exchange_strong_explicit(void *object, void *expected, diff --git a/share/libc/stdio.c b/share/libc/stdio.c index 5db9ebdf4af..eda30573e2d 100644 --- a/share/libc/stdio.c +++ b/share/libc/stdio.c @@ -251,7 +251,7 @@ enum length_modifier { }; int vfscanf(FILE * restrict stream, const char * restrict format, va_list arg) { - char *p = format; + const char *p = format; char conversion_counter = 0; while (*p) { if (*p == '%') { @@ -429,8 +429,11 @@ int vfscanf(FILE * restrict stream, const char * restrict format, va_list arg) { *va_arg(arg, double*) = Frama_C_double_interval(-DBL_MAX, DBL_MAX); break; case UPPER_L: - *va_arg(arg, long double*) = - Frama_C_long_double_interval(-LDBL_MAX, LDBL_MAX); + // TODO: use Frama_C_long_double_interval when it will be supported + { + volatile long double vld; + *va_arg(arg, long double*) = vld; + } break; default: // Undefined behavior diff --git a/share/libc/stdio.h b/share/libc/stdio.h index e6978f505ec..20b060c2f08 100644 --- a/share/libc/stdio.h +++ b/share/libc/stdio.h @@ -589,6 +589,7 @@ extern ssize_t getline(char **lineptr, size_t *n, FILE *stream); /*@ requires valid_or_null_buff: buf == \null || \valid((char*)buf + (0 .. size-1)); requires valid_mode: valid_read_string(mode); + allocates buf; assigns __fc_errno \from indirect: buf, indirect: size, indirect: mode[0..strlen(mode)]; assigns \result \from __fc_p_fopen, @@ -598,7 +599,6 @@ extern ssize_t getline(char **lineptr, size_t *n, FILE *stream); ensures errno_set: __fc_errno == \old(errno) || __fc_errno \in {EINVAL, EMFILE, ENOMEM}; - allocates buf; */ extern FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode); @@ -610,12 +610,12 @@ extern FILE *fmemopen(void *restrict buf, size_t size, /*@ requires valid_strp: \valid(strp); requires valid_fmt: valid_read_string(fmt); + allocates *strp; assigns __fc_heap_status \from indirect:fmt[0 ..], __fc_heap_status; assigns \result \from indirect:fmt[0 ..], indirect:__fc_heap_status; assigns *strp \from fmt[0 ..], indirect:__fc_heap_status; //missing: variadic arguments ensures result_error_or_written_bytes: \result == -1 || \result >= 0; - allocates *strp; */ extern int asprintf(char **strp, const char *fmt, ...); @@ -623,13 +623,13 @@ extern int asprintf(char **strp, const char *fmt, ...); /*@ requires valid_strp: \valid(strp); requires valid_fmt: valid_read_string(fmt); + allocates *strp; assigns __fc_heap_status \from indirect:fmt[0 ..], indirect:ap, __fc_heap_status; assigns \result \from indirect:fmt[0 ..], indirect:__fc_heap_status; assigns *strp \from fmt[0 ..], ap, indirect:__fc_heap_status; //missing: variadic arguments ensures result_error_or_written_bytes: \result == -1 || \result >= 0; - allocates *strp; */ extern int vasprintf(char **restrict strp, const char *restrict fmt, va_list ap); diff --git a/share/libc/stdlib.h b/share/libc/stdlib.h index d792f95c989..4ac3ce4bd90 100644 --- a/share/libc/stdlib.h +++ b/share/libc/stdlib.h @@ -377,8 +377,8 @@ extern long int jrand48 (unsigned short xsubi[3]); behavior no_allocation: assumes cannot_allocate: !is_allocable(nmemb * size); - assigns \result \from \nothing; allocates \nothing; + assigns \result \from \nothing; ensures null_result: \result == \null; complete behaviors; @@ -395,8 +395,8 @@ extern void *calloc(size_t nmemb, size_t size); @ ensures allocation: \fresh(\result,size); @ behavior no_allocation: @ assumes cannot_allocate: !is_allocable(size); - @ assigns \result \from \nothing; @ allocates \nothing; + @ assigns \result \from \nothing; @ ensures null_result: \result==\null; @ complete behaviors; @ disjoint behaviors; @@ -412,8 +412,8 @@ extern void *malloc(size_t size); @ ensures freed: \allocable(p); @ behavior no_deallocation: @ assumes null_p: p==\null; - @ assigns \nothing; @ frees \nothing; + @ assigns \nothing; @ complete behaviors; @ disjoint behaviors; @*/ @@ -716,8 +716,8 @@ extern size_t wcstombs(char * restrict s, ensures result_zero: \result == 0; behavior no_allocation: assumes cannot_allocate: !is_allocable(size); - assigns \result \from indirect:alignment; allocates \nothing; + assigns \result \from indirect:alignment; ensures result_non_zero: \result < 0 || \result > 0; complete behaviors; disjoint behaviors; @@ -779,14 +779,15 @@ extern int mkstemps(char *templat, int suffixlen); assumes valid_file_name: valid_read_string(file_name); assumes resolved_name_null: resolved_name == \null; assumes cannot_allocate: !is_allocable(PATH_MAX); - assigns \result \from \nothing; allocates \nothing; + assigns \result \from \nothing; ensures null_result: \result == \null; ensures errno_set: __fc_errno == ENOMEM; behavior resolved_name_buffer: assumes valid_file_name: valid_read_string(file_name); assumes allocated_resolved_name_or_fail: \valid(resolved_name+(0 .. PATH_MAX-1)); + allocates \nothing; assigns \result \from resolved_name; assigns resolved_name[0 .. PATH_MAX-1] \from indirect:file_name[0..]; ensures valid_string_resolved_name: valid_string(resolved_name) @@ -794,15 +795,14 @@ extern int mkstemps(char *templat, int suffixlen); // missing: assigns \result, // resolved_name[0 .. PATH_MAX-1] \from 'filesystem'; ensures resolved_result: \result == resolved_name; - allocates \nothing; behavior filesystem_error: assumes valid_file_name: valid_read_string(file_name); + allocates \nothing; assigns \result, __fc_errno \from indirect:file_name[0..]; // missing: indirect:'filesystem'; ensures null_result: \result == \null; ensures errno_set: __fc_errno \in {EACCES, EIO, ELOOP, ENAMETOOLONG, ENOENT, ENOTDIR}; - allocates \nothing; */ extern char *realpath(const char *restrict file_name, char *restrict resolved_name); diff --git a/share/libc/string.h b/share/libc/string.h index 0d6379e24f0..9ef1f1620be 100644 --- a/share/libc/string.h +++ b/share/libc/string.h @@ -528,8 +528,8 @@ extern void *memmem(const void *haystack, size_t haystacklen, @ valid_string(\result) && strcmp(\result,s) == 0; @ behavior no_allocation: @ assumes cannot_allocate: !is_allocable(strlen(s)); - @ assigns \result \from \nothing; @ allocates \nothing; + @ assigns \result \from \nothing; @ ensures result_null: \result == \null; @*/ extern char *strdup (const char *s); @@ -550,8 +550,8 @@ extern char *strdup (const char *s); @ strncmp(\result,s,n) == 0; @ behavior no_allocation: @ assumes cannot_allocate: !is_allocable(\min(strlen(s), n+1)); - @ assigns \result \from \nothing; @ allocates \nothing; + @ assigns \result \from \nothing; @ ensures result_null: \result == \null; @*/ extern char *strndup (const char *s, size_t n); diff --git a/share/libc/wchar.h b/share/libc/wchar.h index 645abea7371..c3a5d51c94b 100644 --- a/share/libc/wchar.h +++ b/share/libc/wchar.h @@ -273,15 +273,16 @@ extern int wcscasecmp(const wchar_t *ws1, const wchar_t *ws2); assigns \result \from indirect:ws[0..wcslen(ws)], indirect:__fc_heap_status; behavior allocation: assumes can_allocate: is_allocable(wcslen(ws)); - assigns __fc_heap_status \from indirect:ws, __fc_heap_status; + assigns __fc_heap_status \from indirect:ws[0 .. wcslen(ws), + __fc_heap_status; assigns \result \from indirect:ws[0..wcslen(ws)], indirect:__fc_heap_status; ensures allocation: \fresh(\result,wcslen(ws) * sizeof(wchar_t)); ensures result_valid_string_and_same_contents: valid_wstring(\result) && wcscmp(\result,ws) == 0; behavior no_allocation: assumes cannot_allocate: !is_allocable(wcslen(ws)); - assigns \result \from \nothing; allocates \nothing; + assigns \result \from \nothing; ensures result_null: \result == \null; */ extern wchar_t *wcsdup(const wchar_t *ws); -- GitLab