Skip to content
Snippets Groups Projects
stdlib.h 26.09 KiB
/**************************************************************************/
/*                                                                        */
/*  This file is part of Frama-C.                                         */
/*                                                                        */
/*  Copyright (C) 2007-2021                                               */
/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
/*         alternatives)                                                  */
/*                                                                        */
/*  you can redistribute it and/or modify it under the terms of the GNU   */
/*  Lesser General Public License as published by the Free Software       */
/*  Foundation, version 2.1.                                              */
/*                                                                        */
/*  It is distributed in the hope that it will be useful,                 */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*  GNU Lesser General Public License for more details.                   */
/*                                                                        */
/*  See the GNU Lesser General Public License version 2.1                 */
/*  for more details (enclosed in the file licenses/LGPLv2.1).            */
/*                                                                        */
/**************************************************************************/

/* ISO C: 7.20 */
#ifndef __FC_STDLIB
#define __FC_STDLIB
#include "features.h"
__PUSH_FC_STDLIB
#include "__fc_machdep.h"
#include "__fc_define_size_t.h"
#include "__fc_define_wchar_t.h"
#include "__fc_alloc_axiomatic.h"
#include "__fc_string_axiomatic.h"

__BEGIN_DECLS

#ifndef __div_t_defined
typedef struct __fc_div_t {
  int quot;              /* Quotient.  */
  int rem;               /* Remainder.  */
} div_t;
#define __div_t_defined
#endif

#ifndef __ldiv_t_defined
typedef struct __fc_ldiv_t {
  long int quot;              /* Quotient.  */
  long int rem;               /* Remainder.  */
} ldiv_t;
#define __ldiv_t_defined
#endif

#ifndef __lldiv_t_defined
typedef struct __fc_lldiv_t {
  long long int quot;              /* Quotient.  */
  long long int rem;               /* Remainder.  */
} lldiv_t;
#define __lldiv_t_defined
#endif

#include "__fc_define_null.h"

/* These could be customizable */
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0

#include "limits.h"

#define RAND_MAX __FC_RAND_MAX
#define MB_CUR_MAX __FC_MB_CUR_MAX
/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
 */
extern double atof(const char *nptr);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
 */
extern int atoi(const char *nptr);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
 */
extern long int atol(const char *nptr);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
 */
extern long long int atoll(const char *nptr);

/* See ISO C: 7.20.1.3 to complete these specifications */

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern double strtod(const char * restrict nptr,
     char ** restrict endptr);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern float strtof(const char * restrict nptr,
     char ** restrict endptr);
/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..];
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern long double strtold(const char * restrict nptr,
     char ** restrict endptr);

/* TODO: See ISO C 7.20.1.4 to complete these specifications */
/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  requires base_range: base == 0 || 2 <= base <= 36;
  assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern long int strtol(
     const char * restrict nptr,
     char ** restrict endptr,
     int base);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  requires base_range: base == 0 || 2 <= base <= 36;
  assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern long long int strtoll(
     const char * restrict nptr,
     char ** restrict endptr,
     int base);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  requires base_range: base == 0 || 2 <= base <= 36;
  assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern unsigned long int strtoul(
     const char * restrict nptr,
     char ** restrict endptr,
     int base);

/*@
  requires valid_nptr: \valid_read(nptr); // cannot be precise, valid_read_string too strong
  requires separation: \separated(nptr, endptr);
  requires base_range: base == 0 || 2 <= base <= 36;
  assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
  behavior no_storage:
    assumes null_endptr: endptr == \null;
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
  behavior store_position:
    assumes nonnull_endptr: endptr != \null;
    requires valid_endptr: \valid(endptr);
    assigns \result \from indirect:nptr, indirect:nptr[0 ..], indirect:base;
    assigns *endptr \from nptr, indirect:nptr[0 ..], indirect:endptr, indirect:base;
    ensures initialization: \initialized(endptr);
    ensures valid_endptr: \valid_read(endptr);
    ensures position_subset: \subset(*endptr, nptr + (0 ..));
  complete behaviors;
  disjoint behaviors;
*/
extern unsigned long long int strtoull(
     const char * restrict nptr,
     char ** restrict endptr,
     int base);

//@ ghost extern int __fc_random_counter __attribute__((unused));
const unsigned long __fc_rand_max = __FC_RAND_MAX;

/* ISO C: 7.20.2 */
/*@ assigns \result \from __fc_random_counter ;
  @ assigns __fc_random_counter \from __fc_random_counter ;
  @ ensures result_range: 0 <= \result <= __fc_rand_max ;
*/
extern int rand(void);

/*@ assigns __fc_random_counter \from seed ; */
extern void srand(unsigned int seed);

/*@
  assigns \result \from __fc_random_counter;
  ensures result_range: 0 <= \result <= __fc_rand_max;
*/
extern long int random(void);

/*@ assigns __fc_random_counter \from seed; */
extern void srandom(unsigned int seed);

// used to check if some *48() functions have called the seed initializer
int __fc_random48_init;

__FC_EXTERN unsigned short __fc_random48_counter[3];
unsigned short *__fc_p_random48_counter = __fc_random48_counter;

/*@
  assigns __fc_random48_counter[0..2] \from seed;
  assigns __fc_random48_init \from \nothing;
  ensures random48_initialized: __fc_random48_init == 1;
*/
extern void srand48 (long int seed);

/*@
  requires initialization:initialized_seed16v: \initialized(seed16v+(0..2));
  assigns __fc_random48_counter[0..2] \from indirect:seed16v[0..2];
  assigns __fc_random48_init \from \nothing;
  assigns \result \from __fc_p_random48_counter;
  ensures random48_initialized: __fc_random48_init == 1;
  ensures result_counter: \result == __fc_p_random48_counter;
*/
extern unsigned short *seed48(unsigned short seed16v[3]);

/*@
  assigns __fc_random48_counter[0..2] \from param[0..5];
  assigns __fc_random48_init \from \nothing;
  ensures random48_initialized: __fc_random48_init == 1;
*/
extern void lcong48(unsigned short param[7]);

/*@
  requires random48_initialized: __fc_random48_init == 1;
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: \is_finite(\result) && 0.0 <= \result < 1.0;
*/
extern double drand48(void);

/*@
  requires initialization:initialized_xsubi: \initialized(xsubi+(0..2));
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: \is_finite(\result) && 0.0 <= \result < 1.0;
*/
extern double erand48(unsigned short xsubi[3]);

/*@
  requires random48_initialized: __fc_random48_init == 1;
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: 0 <= \result < 2147483648;
*/
extern long int lrand48 (void);

/*@
  requires initialization:initialized_xsubi: \initialized(xsubi+(0..2));
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: 0 <= \result < 2147483648;
*/
extern long int nrand48 (unsigned short xsubi[3]);

/*@
  requires random48_initialized: __fc_random48_init == 1;
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: -2147483648 <= \result < 2147483648;
*/
extern long int mrand48 (void);

/*@
  requires initialization:initialized_xsubi: \initialized(xsubi+(0..2));
  assigns __fc_random48_counter[0..2] \from __fc_random48_counter[0..2];
  assigns \result \from __fc_random48_counter[0..2];
  ensures result_range: -2147483648 <= \result < 2147483648;
*/
extern long int jrand48 (unsigned short xsubi[3]);

/* ISO C: 7.20.3.1 */
/*@
  allocates \result;
  assigns __fc_heap_status \from indirect:nmemb, indirect:size, __fc_heap_status;
  assigns \result \from indirect:nmemb, indirect:size,
                        indirect:__fc_heap_status;

  behavior allocation:
    assumes can_allocate: is_allocable(nmemb * size);
    ensures allocation: \fresh(\result, nmemb * size);
    ensures initialization: \initialized(((char *)\result)+(0..nmemb*size-1));
    ensures zero_initialization: \subset(((char *)\result)[0..nmemb*size-1], {0});

  behavior no_allocation:
    assumes cannot_allocate: !is_allocable(nmemb * size);
    assigns \result \from \nothing;
    allocates \nothing;
    ensures null_result: \result == \null;

  complete behaviors;
  disjoint behaviors; */
extern void *calloc(size_t nmemb, size_t size);
 
/*@ allocates \result;
  @ assigns __fc_heap_status \from size, __fc_heap_status;
  @ assigns \result \from indirect:size, indirect:__fc_heap_status;
  @ behavior allocation:
  @   assumes can_allocate: is_allocable(size);
  @   assigns __fc_heap_status \from size, __fc_heap_status;
  @   assigns \result \from indirect:size, indirect:__fc_heap_status;
  @   ensures allocation: \fresh(\result,size);
  @ behavior no_allocation:
  @   assumes cannot_allocate: !is_allocable(size);
  @   assigns \result \from \nothing;
  @   allocates \nothing;
  @   ensures null_result: \result==\null;
  @ complete behaviors;
  @ disjoint behaviors;
  @*/
extern void *malloc(size_t size);

/*@ requires freeable: p==\null || \freeable(p);
  @ frees p;
  @ assigns  __fc_heap_status \from __fc_heap_status;
  @ behavior deallocation:
  @   assumes  nonnull_p: p!=\null;
  @   assigns  __fc_heap_status \from __fc_heap_status;
  @   ensures  freed: \allocable(p);
  @ behavior no_deallocation:
  @   assumes  null_p: p==\null;
  @   assigns  \nothing;
  @   frees    \nothing;
  @ complete behaviors;
  @ disjoint behaviors;
  @*/
extern void free(void *p);
/*@
   requires freeable: ptr == \null || \freeable(ptr);
   allocates \result;
   frees     ptr;
   assigns   __fc_heap_status \from __fc_heap_status;
   assigns   \result \from size, ptr, __fc_heap_status;

   behavior allocation:
     assumes   can_allocate: is_allocable(size);
     allocates \result;
     assigns   \result \from size, __fc_heap_status;
     ensures   allocation: \fresh(\result,size);

   behavior deallocation:
     assumes   nonnull_ptr: ptr != \null;
     assumes   can_allocate: is_allocable(size);
     frees     ptr;
     ensures   freed: \allocable(ptr);
     ensures   freeable: \result == \null || \freeable(\result);

   behavior fail:
     assumes cannot_allocate: !is_allocable(size);
     allocates \nothing;
     frees     \nothing;
     assigns   \result \from size, __fc_heap_status;
     ensures   null_result: \result == \null;

   complete behaviors;
   disjoint behaviors allocation, fail;
   disjoint behaviors deallocation, fail;
  */
extern void *realloc(void *ptr, size_t size);


/* ISO C: 7.20.4 */

/*@
  assigns \exit_status \from \nothing;
  exits status: \exit_status != EXIT_SUCCESS;
  ensures never_terminates: \false;
 */
extern void abort(void) __attribute__ ((__noreturn__));

/*@ assigns \result \from \nothing ;*/
extern int atexit(void (*func)(void));

/*@ assigns \result \from \nothing ;*/
extern int at_quick_exit(void (*func)(void));

/*@
  assigns \exit_status \from status;
  exits status: \exit_status == status;
  ensures never_terminates: \false;
*/
extern void exit(int status) __attribute__ ((__noreturn__));

/*@
  assigns \nothing;
  ensures never_terminates: \false;
*/
extern void _Exit(int status) __attribute__ ((__noreturn__));

extern char *__fc_env[ARG_MAX];

/*@
  requires valid_name: valid_read_string(name);
  assigns \result \from __fc_env[0..], indirect:name, name[0 ..];
  ensures null_or_valid_result: \result == \null || \valid(\result);
 */
extern char *getenv(const char *name);

/*@
  requires valid_string: valid_read_string(string);
  assigns __fc_env[0..] \from __fc_env[0..], string;
  assigns \result \from indirect:__fc_env[0..], indirect:string;
*/
extern int putenv(char *string);

/*@
  requires valid_name: valid_read_string(name);
  requires valid_value: valid_read_string(value);
  assigns \result, __fc_env[0..]
    \from __fc_env[0..], indirect:name, indirect:name[0 ..],
          indirect:value, indirect:value[0 ..], indirect:overwrite;
  ensures result_ok_or_error: \result == 0 || \result == -1;
*/
extern int setenv(const char *name, const char *value, int overwrite);

/*@
  requires valid_name: valid_read_string(name);
  assigns \result, __fc_env[0..]
    \from __fc_env[0..], indirect:name, indirect:name[0 ..];
  ensures result_ok_or_error: \result == 0 || \result == -1;
*/
extern int unsetenv(const char *name);

/*@
  assigns \nothing;
  ensures never_terminates: \false;
 */
extern void quick_exit(int status) __attribute__ ((__noreturn__));

/*@
  requires null_or_valid_string_command:
     command == \null || valid_read_string(command);
  assigns \result \from indirect:command, indirect:command[0 ..];
*/
extern int system(const char *command);

/* ISO C: 7.20.5 */

/* TODO: use one of the well known specification with high order compare :-) */
// NOTE: the assigns of function [compar] are not currently taken into account
// by ACSL. If [compar] is not purely functional, the result may be unsound.
// To ensure soundness, you should manually give a specification to the
// comparison function that is equivalent to:
//     assigns \result \from *(<type>*)a, *(<type>*)b;
// where <type> is the type of the compared arguments.
/*@
  requires valid_function_compar: \valid_function(compar);
  assigns \result \from indirect:key, ((char*)key)[0 .. size-1], base,
                        ((char*)base)[0 .. size * (nmemb-1)], indirect:nmemb,
                        indirect:size, indirect:*compar;
  ensures null_or_correct_result: \result == \null ||
          \subset(\result, (void*)(((char*)base) + (0 .. size * (nmemb-1))));
*/
extern void *bsearch(const void *key, const void *base, size_t nmemb,
                     size_t size, int (*compar)(const void *, const void *));

// NOTE: the assigns of function [compar] are not currently taken into account
// by ACSL. If [compar] is not purely functional, the result may be unsound.
/*@
  requires valid_function_compar: \valid_function(compar);
  assigns ((char*)base)[0 ..] \from indirect:base, ((char*)base)[0 ..],
                                    indirect:nmemb, indirect:size,
                                    indirect:compar, indirect:*compar;
 */
extern void qsort(void *base, size_t nmemb, size_t size,
             int (*compar)(const void *, const void *));
/* ISO C: 7.20.6 */

/*@
  requires abs_representable: j > INT_MIN;
  assigns \result \from j;
  behavior negative:
    assumes negative: j < 0;
    ensures opposite_result: \result == -j;
  behavior nonnegative:
    assumes nonnegative: j >= 0;
    ensures same_result: \result == j;
  complete behaviors;
  disjoint behaviors;
 */
extern int abs(int j);

/*@
  requires abs_representable: j > LONG_MIN ;
  assigns \result \from j;
  behavior negative:
    assumes negative: j < 0;
    ensures opposite_result: \result == -j;
  behavior nonnegative:
    assumes nonnegative: j >= 0;
    ensures same_result: \result == j;
  complete behaviors;
  disjoint behaviors;
 */
extern long int labs(long int j);

/*@
  requires abs_representable: j > LLONG_MIN ;
  assigns \result \from j;
  behavior negative:
    assumes negative: j < 0;
    ensures opposite_result: \result == -j;
  behavior nonnegative:
    assumes nonnegative: j >= 0;
    ensures same_result: \result == j;
  complete behaviors;
  disjoint behaviors;
 */
extern long long int llabs(long long int j);

/*@ assigns \result \from numer,denom ; */
extern div_t div(int numer, int denom);
/*@ assigns \result \from numer,denom ; */
extern ldiv_t ldiv(long int numer, long int denom);
/*@ assigns \result \from numer,denom ; */
extern lldiv_t lldiv(long long int numer, long long int denom);

/* ISO C: 7.20.7 */

//@ ghost extern int __fc_mblen_state;

/*@ assigns \result, __fc_mblen_state \from
    indirect:s, indirect:s[0 ..], indirect:n, __fc_mblen_state; */
extern int mblen(const char *s, size_t n);

//@ ghost extern int __fc_mbtowc_state;

/*@
  requires separation: \separated(pwc, s);
  assigns \result \from indirect:s, indirect:s[0 .. n-1], indirect:n,
                        __fc_mbtowc_state;
  assigns pwc[0 .. \result-1], __fc_mbtowc_state
    \from indirect:s, s[0 .. n-1], indirect:n, __fc_mbtowc_state;
  ensures consumed_range: \result <= n;
*/
extern int mbtowc(wchar_t * restrict pwc,
     const char * restrict s,
     size_t n);

//@ ghost extern int __fc_wctomb_state;

/*@
  //requires room_string: \valid(s + (0 .. __fc_mb_cur_max - 1));
  assigns \result \from indirect:wc, __fc_wctomb_state;
  assigns s[0 ..], __fc_wctomb_state \from wc, __fc_wctomb_state;
*/
extern int wctomb(char *s, wchar_t wc);

/* ISO C: 7.20.8 */

/*@
  requires separation: \separated(pwcs, s);
  assigns \result \from indirect:s, indirect:s[0 .. n-1], indirect:n;
  assigns pwcs[0 .. n-1] \from indirect:s, s[0 .. n-1], indirect:n;
*/
extern size_t mbstowcs(wchar_t * restrict pwcs,
     const char * restrict s,
     size_t n);

/*@
  requires separation: \separated(s, pwcs);
  assigns \result \from indirect:pwcs, indirect:pwcs[0 .. n-1], indirect:n;
  assigns s[0 .. n-1] \from indirect:pwcs, pwcs[0 .. n-1], indirect:n;
*/
extern size_t wcstombs(char * restrict s,
     const wchar_t * restrict pwcs,
     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);

/*@
  // missing: requires 'last 6 characters of template must be XXXXXX'
  // missing: assigns \result, templat[0..] \from 'filesystem', 'RNG';
  requires valid_template: valid_string(templat);
  requires template_len: strlen(templat) >= 6;
  assigns templat[0..] \from \nothing;
  assigns \result \from \nothing;
  ensures result_error_or_valid_fd: \result == -1 ||
                                    0 <= \result < __FC_FOPEN_MAX;
 */
extern int mkstemp(char *templat);

/*@
  // missing: requires 'last (6+suffixlen) characters of template must be X's'
  // missing: assigns \result, templat[0..] \from 'filesystem', 'RNG';
  requires valid_template: valid_string(templat);
  requires template_len: strlen(templat) >= 6 + suffixlen;
  requires non_negative_suffixlen: suffixlen >= 0;
  assigns templat[0..] \from \nothing;
  assigns \result \from \nothing;
  ensures result_error_or_valid_fd: \result == -1 ||
                                    0 <= \result < __FC_FOPEN_MAX;
 */
extern int mkstemps(char *templat, int suffixlen);

// This function may allocate memory for the result, which is not supported by
// some plugins such as Eva. In such cases, it is preferable to use the stub
// provided in stdlib.c.
extern char *realpath(const char *restrict file_name,
                      char *restrict resolved_name);

// Non-POSIX; GNU extension
// This function may allocate memory for the result, which is not supported by
// some plugins such as Eva. In such cases, it is preferable to use the stub
// provided in stdlib.c.
extern char *canonicalize_file_name(const char *path);

__END_DECLS

__POP_FC_STDLIB
#endif