diff --git a/share/libc/stdlib.c b/share/libc/stdlib.c index 72dd24cc238641547c7bdcd5f4855cc7f099936f..d9c40ce3983b2ad6ee27c15da26fba50d6889453 100644 --- a/share/libc/stdlib.c +++ b/share/libc/stdlib.c @@ -187,4 +187,19 @@ int unsetenv(const char *name) char __fc_strerror[64]; #endif +// Note: this implementation does not check the alignment, since it cannot +// currently be specified in the memory model of most plug-ins +int posix_memalign(void **memptr, size_t alignment, size_t size) { + // By default, specifications in the libc are ignored for defined functions, + // and since we do not actually use alignment, we need to check its validity. + // The assertion below is the requires in the specification. + /*@ assert alignment_is_a_suitable_power_of_two: + alignment >= sizeof(void*) && + ((size_t)alignment & ((size_t)alignment - 1)) == 0; + */ + *memptr = malloc(size); + if (!*memptr) return ENOMEM; + return 0; +} + __POP_FC_STDLIB diff --git a/share/libc/stdlib.h b/share/libc/stdlib.h index acdbbf87f659a078e3a89127771f0089eb11704c..e69ed2aa5b7dd00a0a704e72dc6e398b8036dfe2 100644 --- a/share/libc/stdlib.h +++ b/share/libc/stdlib.h @@ -594,6 +594,34 @@ extern size_t wcstombs(char * restrict s, size_t n); +// Note: this specification should ideally use a more specific predicate, +// such as 'is_allocable_aligned(alignment, size)'. +/*@ + requires valid_memptr: \valid(memptr); + requires alignment_is_a_suitable_power_of_two: + alignment >= sizeof(void*) && + ((size_t)alignment & ((size_t)alignment - 1)) == 0; + allocates *memptr; + assigns __fc_heap_status \from indirect:alignment, size, __fc_heap_status; + assigns \result \from indirect:alignment, indirect:size, + indirect:__fc_heap_status; + behavior allocation: + assumes can_allocate: is_allocable(size); + assigns __fc_heap_status \from indirect:alignment, size, __fc_heap_status; + assigns \result \from indirect:alignment, indirect:size, + indirect:__fc_heap_status; + ensures allocation: \fresh(*memptr,size); + ensures result_zero: \result == 0; + behavior no_allocation: + assumes cannot_allocate: !is_allocable(size); + assigns \result \from indirect:alignment; + allocates \nothing; + ensures result_non_zero: \result < 0 || \result > 0; + complete behaviors; + disjoint behaviors; + */ +extern int posix_memalign(void **memptr, size_t alignment, size_t size); + __END_DECLS __POP_FC_STDLIB diff --git a/src/plugins/value/utils/library_functions.ml b/src/plugins/value/utils/library_functions.ml index 0cb2c758547d844a1af22eb5b4376b1d3c459a98..f9abcf51c3c3ddeab1fdcc9152b23ce7cf61f99e 100644 --- a/src/plugins/value/utils/library_functions.ml +++ b/src/plugins/value/utils/library_functions.ml @@ -79,6 +79,7 @@ let unsupported_specifications = "strdup", "string.c"; "strndup", "string.c"; "getenv", "stdlib.c"; + "posix_memalign", "stdlib.c"; "putenv", "stdlib.c"; "setenv", "stdlib.c"; "unsetenv", "stdlib.c" diff --git a/tests/libc/oracle/coverage.res.oracle b/tests/libc/oracle/coverage.res.oracle index 022ec6cf4bf93925c11032ef63434f829269cac5..6c5fe3be202d1c7a64d8bd4f0dbc15e336cac7d4 100644 --- a/tests/libc/oracle/coverage.res.oracle +++ b/tests/libc/oracle/coverage.res.oracle @@ -28,7 +28,7 @@ main: 4 stmts out of 4 (100.0%) [metrics] Eva coverage statistics ======================= - Syntactically reachable functions = 2 (out of 75) + Syntactically reachable functions = 2 (out of 76) Semantically reached functions = 2 Coverage estimation = 100.0% [metrics] Statements analyzed by Eva diff --git a/tests/libc/oracle/fc_libc.0.res.oracle b/tests/libc/oracle/fc_libc.0.res.oracle index 60e8d3f8a81faf8bef3d2ea162812f2ec0c00651..27fb20cb71c1294c6261d45bae24f3d04dceeef2 100644 --- a/tests/libc/oracle/fc_libc.0.res.oracle +++ b/tests/libc/oracle/fc_libc.0.res.oracle @@ -13,7 +13,7 @@ [eva] ====== VALUES COMPUTED ====== [eva:final-states] Values at end of function main: -[metrics] Defined functions (73) +[metrics] Defined functions (74) ====================== Frama_C_double_interval (0 call); Frama_C_float_interval (0 call); Frama_C_interval (13 calls); Frama_C_nondet (11 calls); @@ -28,14 +28,14 @@ isprint (0 call); ispunct (0 call); isspace (1 call); isupper (0 call); isxdigit (0 call); localeconv (0 call); main (0 call); memchr (0 call); memcmp (0 call); memcpy (2 calls); memmove (0 call); memrchr (0 call); - memset (1 call); putenv (0 call); setenv (0 call); setlocale (0 call); - strcasecmp (0 call); strcat (0 call); strchr (3 calls); strcmp (0 call); - strcpy (0 call); strdup (0 call); strerror (0 call); strlen (6 calls); - strncat (0 call); strncmp (0 call); strncpy (0 call); strndup (0 call); - strnlen (0 call); strrchr (0 call); strstr (0 call); tolower (0 call); - toupper (0 call); unsetenv (0 call); wcscat (0 call); wcscpy (0 call); - wcslen (2 calls); wcsncat (0 call); wcsncpy (0 call); wmemcpy (0 call); - wmemset (0 call); + memset (1 call); posix_memalign (0 call); putenv (0 call); setenv (0 call); + setlocale (0 call); strcasecmp (0 call); strcat (0 call); strchr (3 calls); + strcmp (0 call); strcpy (0 call); strdup (0 call); strerror (0 call); + strlen (6 calls); strncat (0 call); strncmp (0 call); strncpy (0 call); + strndup (0 call); strnlen (0 call); strrchr (0 call); strstr (0 call); + tolower (0 call); toupper (0 call); unsetenv (0 call); wcscat (0 call); + wcscpy (0 call); wcslen (2 calls); wcsncat (0 call); wcsncpy (0 call); + wmemcpy (0 call); wmemset (0 call); Undefined functions (360) ========================= @@ -104,7 +104,7 @@ localtime (0 call); log (0 call); log10 (0 call); log10f (0 call); log10l (0 call); log2 (0 call); log2f (0 call); log2l (0 call); logf (0 call); logl (0 call); longjmp (0 call); lrand48 (0 call); - malloc (6 calls); mblen (0 call); mbstowcs (0 call); mbtowc (0 call); + malloc (7 calls); mblen (0 call); mbstowcs (0 call); mbtowc (0 call); memoverlap (1 call); mkdir (0 call); mktime (0 call); nan (0 call); nanf (0 call); nanl (0 call); nanosleep (0 call); ntohl (0 call); ntohs (0 call); open (0 call); openat (0 call); opendir (0 call); @@ -162,18 +162,18 @@ Global metrics ============== - Sloc = 948 - Decision point = 183 + Sloc = 956 + Decision point = 184 Global variables = 58 - If = 174 + If = 175 Loop = 40 - Goto = 78 - Assignment = 379 - Exit point = 73 - Function = 433 - Function call = 73 - Pointer dereferencing = 146 - Cyclomatic complexity = 256 + Goto = 79 + Assignment = 382 + Exit point = 74 + Function = 434 + Function call = 74 + Pointer dereferencing = 148 + Cyclomatic complexity = 258 /* Generated by Frama-C */ #include "__fc_builtin.c" #include "__fc_builtin.h" diff --git a/tests/libc/oracle/fc_libc.1.res.oracle b/tests/libc/oracle/fc_libc.1.res.oracle index ca6d82677730323b0caf2c381e8440319f4a8896..d649b563c77dcd5d8464e949284cad01c611a625 100644 --- a/tests/libc/oracle/fc_libc.1.res.oracle +++ b/tests/libc/oracle/fc_libc.1.res.oracle @@ -1906,6 +1906,8 @@ extern size_t mbstowcs(wchar_t * __restrict pwcs, char const * __restrict s, extern size_t wcstombs(char * __restrict s, wchar_t const * __restrict pwcs, size_t n); +int posix_memalign(void **memptr, size_t alignment, size_t size); + int glob(char const *pattern, int flags, int (*errfunc)(char const *epath, int eerrno), glob_t *pglob) { @@ -4346,6 +4348,59 @@ int unsetenv(char const *name) return_label: return __retres; } +/*@ requires valid_memptr: \valid(memptr); + requires + alignment_is_a_suitable_power_of_two: + alignment ≥ sizeof(void *) ∧ + ((unsigned int)alignment & ((unsigned int)alignment - 1)) ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + allocates *\old(memptr); + + behavior allocation: + assumes can_allocate: is_allocable(size); + ensures allocation: \fresh{Old, Here}(*\old(memptr),\old(size)); + ensures result_zero: \result ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + + behavior no_allocation: + assumes cannot_allocate: ¬is_allocable(size); + ensures result_non_zero: \result < 0 ∨ \result > 0; + assigns \result; + assigns \result \from (indirect: alignment); + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int posix_memalign(void **memptr, size_t alignment, size_t size) +{ + int __retres; + /*@ + assert + alignment_is_a_suitable_power_of_two: + alignment ≥ sizeof(void *) ∧ + ((unsigned int)alignment & ((unsigned int)alignment - 1)) ≡ 0; + */ + ; + *memptr = malloc(size); + if (! *memptr) { + __retres = 12; + goto return_label; + } + __retres = 0; + return_label: return __retres; +} + /*@ requires valid_dest: valid_or_empty(dest, n); requires valid_src: valid_read_or_empty(src, n); requires diff --git a/tests/libc/oracle/stdlib_c.0.res.oracle b/tests/libc/oracle/stdlib_c.0.res.oracle index b95eac34de167bf145daa4266e881ffb644afe7a..1a7d60180779c859e8ad53b009b2d574aa0ec047 100644 --- a/tests/libc/oracle/stdlib_c.0.res.oracle +++ b/tests/libc/oracle/stdlib_c.0.res.oracle @@ -76,9 +76,42 @@ [eva:malloc] tests/libc/stdlib_c.c:32: resizing variable `__calloc_w_main_l32' (0..31/34359738367) to fit 0..63/34359738367 +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:37. +[eva] share/libc/stdlib.c:197: + assertion 'alignment_is_a_suitable_power_of_two' got status valid. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: allocating variable __malloc_posix_memalign_l200 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:38. +[eva] using specification for function free +[eva] tests/libc/stdlib_c.c:38: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:38: + function free: precondition 'freeable' got status valid. +[eva] Done for function free +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:39. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: + allocating variable __malloc_posix_memalign_l200_0 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:40. +[eva] tests/libc/stdlib_c.c:40: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:40: + function free: precondition 'freeable' got status valid. +[eva] Done for function free [eva] Recording results for main [eva] done for function main [eva] ====== VALUES COMPUTED ====== +[eva:final-states] Values at end of function posix_memalign: + __fc_heap_status ∈ [--..--] + p_al0 ∈ {{ NULL ; &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ NULL ; &__malloc_posix_memalign_l200_0[0] }} or UNINITIALIZED + __retres ∈ {0; 12} [eva:final-states] Values at end of function main: __fc_heap_status ∈ [--..--] Frama_C_entropy_source ∈ [--..--] @@ -87,5 +120,9 @@ q ∈ {{ NULL ; &__calloc_main_l21[0] }} r ∈ {0} s ∈ {{ NULL ; &__calloc_w_main_l32[0] }} + p_al0 ∈ {{ NULL ; &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ NULL ; &__malloc_posix_memalign_l200_0[0] }} + p_memal_res ∈ {0; 12} + p_memal_res2 ∈ {0; 12} __retres ∈ {0} __calloc_w_main_l32[0..1073741823] ∈ {0; 42} diff --git a/tests/libc/oracle/stdlib_c.1.res.oracle b/tests/libc/oracle/stdlib_c.1.res.oracle index 8dd967128d5fac44717cbb3a39886115ce154149..9021fc4d9d1690f4816abb040418148419280ab1 100644 --- a/tests/libc/oracle/stdlib_c.1.res.oracle +++ b/tests/libc/oracle/stdlib_c.1.res.oracle @@ -95,9 +95,42 @@ [eva:malloc] tests/libc/stdlib_c.c:32: resizing variable `__calloc_w_main_l32' (0..31/34359738367) to fit 0..191/34359738367 +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:37. +[eva] share/libc/stdlib.c:197: + assertion 'alignment_is_a_suitable_power_of_two' got status valid. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: allocating variable __malloc_posix_memalign_l200 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:38. +[eva] using specification for function free +[eva] tests/libc/stdlib_c.c:38: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:38: + function free: precondition 'freeable' got status valid. +[eva] Done for function free +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:39. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: + allocating variable __malloc_posix_memalign_l200_0 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:40. +[eva] tests/libc/stdlib_c.c:40: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:40: + function free: precondition 'freeable' got status valid. +[eva] Done for function free [eva] Recording results for main [eva] done for function main [eva] ====== VALUES COMPUTED ====== +[eva:final-states] Values at end of function posix_memalign: + __fc_heap_status ∈ [--..--] + p_al0 ∈ {{ &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ &__malloc_posix_memalign_l200_0[0] }} or UNINITIALIZED + __retres ∈ {0} [eva:final-states] Values at end of function main: __fc_heap_status ∈ [--..--] Frama_C_entropy_source ∈ [--..--] @@ -106,5 +139,9 @@ q ∈ {{ NULL ; &__calloc_main_l21[0] }} r ∈ {0} s ∈ {{ NULL ; &__calloc_w_main_l32[0] }} + p_al0 ∈ {{ &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ &__malloc_posix_memalign_l200_0[0] }} + p_memal_res ∈ {0} + p_memal_res2 ∈ {0} __retres ∈ {0} __calloc_w_main_l32[0..1073741823] ∈ {0; 42} diff --git a/tests/libc/oracle/stdlib_c.2.res.oracle b/tests/libc/oracle/stdlib_c.2.res.oracle index 8d66691a343b130e4ffd82e0d83ffecc8421c366..c70cca5c9ec4c02a371d875dd9c5978ed6f15c83 100644 --- a/tests/libc/oracle/stdlib_c.2.res.oracle +++ b/tests/libc/oracle/stdlib_c.2.res.oracle @@ -94,6 +94,34 @@ [eva] Done for function memset [eva] Recording results for calloc [eva] Done for function calloc +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:37. +[eva] share/libc/stdlib.c:197: + assertion 'alignment_is_a_suitable_power_of_two' got status valid. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: allocating variable __malloc_posix_memalign_l200 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:38. +[eva] using specification for function free +[eva] tests/libc/stdlib_c.c:38: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:38: + function free: precondition 'freeable' got status valid. +[eva] Done for function free +[eva] computing for function posix_memalign <- main. + Called from tests/libc/stdlib_c.c:39. +[eva] share/libc/stdlib.c:200: Call to builtin Frama_C_malloc_by_stack +[eva] share/libc/stdlib.c:200: + allocating variable __malloc_posix_memalign_l200_0 +[eva] Recording results for posix_memalign +[eva] Done for function posix_memalign +[eva] computing for function free <- main. + Called from tests/libc/stdlib_c.c:40. +[eva] tests/libc/stdlib_c.c:40: Warning: ignoring unsupported \allocates clause +[eva] tests/libc/stdlib_c.c:40: + function free: precondition 'freeable' got status valid. +[eva] Done for function free [eva] Recording results for main [eva] done for function main [eva] ====== VALUES COMPUTED ====== @@ -110,6 +138,11 @@ __malloc_calloc_l72[0..3] ∈ [--..--] or UNINITIALIZED __malloc_calloc_l72_0[0..4294967291] ∈ [--..--] or UNINITIALIZED __malloc_w_calloc_l72_1[0..4294967291] ∈ [--..--] or UNINITIALIZED +[eva:final-states] Values at end of function posix_memalign: + __fc_heap_status ∈ [--..--] + p_al0 ∈ {{ NULL ; &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ NULL ; &__malloc_posix_memalign_l200_0[0] }} or UNINITIALIZED + __retres ∈ {0; 12} [eva:final-states] Values at end of function main: __fc_heap_status ∈ [--..--] Frama_C_entropy_source ∈ [--..--] @@ -118,6 +151,10 @@ q ∈ {{ NULL ; (int *)&__malloc_calloc_l72_0 }} r ∈ {0} s ∈ {{ NULL ; (int *)&__malloc_w_calloc_l72_1 }} or UNINITIALIZED + p_al0 ∈ {{ NULL ; &__malloc_posix_memalign_l200[0] }} + p_al1 ∈ {{ NULL ; &__malloc_posix_memalign_l200_0[0] }} + p_memal_res ∈ {0; 12} + p_memal_res2 ∈ {0; 12} __retres ∈ {0} __malloc_calloc_l72[0..3] ∈ [--..--] or UNINITIALIZED __malloc_calloc_l72_0[0..4294967291] ∈ [--..--] or UNINITIALIZED diff --git a/tests/libc/stdlib_c.c b/tests/libc/stdlib_c.c index 3bb9f5f8b671b06e7652ac3745dc3dea1ccf0cfa..d265774bec565ed9ea9b83b45ff1620f44465221 100644 --- a/tests/libc/stdlib_c.c +++ b/tests/libc/stdlib_c.c @@ -33,5 +33,11 @@ int main() { if (s) s[i-1] = 42; } + char *p_al0, *p_al1; + int p_memal_res = posix_memalign((void**)&p_al0, 32, 0); + free(p_al0); + int p_memal_res2 = posix_memalign((void**)&p_al1, 32, 42); + free(p_al1); + return 0; }