diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index 75a8014972c92d933188bcb17480f0c050a7ab7f..fc3f7cd5925d9bdd595efa5286da61869aff2c7b 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -286,6 +286,7 @@ share/libc/netinet/tcp.h: CEA_LGPL
 share/libc/nl_types.h: CEA_LGPL
 share/libc/poll.h: CEA_LGPL
 share/libc/pthread.h: CEA_LGPL
+share/libc/pwd.c: CEA_LGPL
 share/libc/pwd.h: CEA_LGPL
 share/libc/regex.h: CEA_LGPL
 share/libc/resolv.h: CEA_LGPL
diff --git a/share/libc/__fc_builtin.c b/share/libc/__fc_builtin.c
index 2654932223c2c5f397627cb5e75f75376aaa6a16..b7b973543cc9603fb2bc3946bfa69b80daccbe86 100644
--- a/share/libc/__fc_builtin.c
+++ b/share/libc/__fc_builtin.c
@@ -22,6 +22,7 @@
 
 #include "__fc_builtin.h"
 __PUSH_FC_STDLIB
+#include "limits.h"
 
 /* Those builtins implementations could probably be removed entirely for
    Value, as the spec is informative enough. There remains a slight difference
@@ -30,6 +31,11 @@ __PUSH_FC_STDLIB
 
 int volatile Frama_C_entropy_source;
 
+// Additional entropy sources for some interval functions
+unsigned int volatile __fc_unsigned_int_entropy;
+long volatile __fc_long_entropy;
+unsigned long volatile __fc_unsigned_long_entropy;
+
 //@ assigns Frama_C_entropy_source \from Frama_C_entropy_source;
 void Frama_C_update_entropy(void) {
   Frama_C_entropy_source = Frama_C_entropy_source;
@@ -56,10 +62,10 @@ void *Frama_C_nondet_ptr(void *a, void *b)
 
 int Frama_C_interval(int min, int max)
 {
-  int r,aux;
+  int r, aux;
   Frama_C_update_entropy();
   aux = Frama_C_entropy_source;
-  if ((aux>=min) && (aux <=max))
+  if (aux >= min && aux <= max)
     r = aux;
   else
     r = min;
@@ -68,27 +74,60 @@ int Frama_C_interval(int min, int max)
 
 char Frama_C_char_interval(char min, char max)
 {
-  int r;
-  char aux;
+  return (char)Frama_C_interval(min, max);
+}
+
+float Frama_C_float_interval(float min, float max)
+{
   Frama_C_update_entropy();
-  aux = Frama_C_entropy_source;
-  if ((aux>=min) && (aux <=max))
+  return Frama_C_entropy_source ? min : max;
+}
+
+double Frama_C_double_interval(double min, double max)
+{
+  Frama_C_update_entropy();
+  return Frama_C_entropy_source ? min : max;
+}
+
+unsigned char Frama_C_unsigned_char_interval(unsigned char min, unsigned char max)
+{
+  return (unsigned char)Frama_C_interval(min, max);
+}
+
+unsigned int Frama_C_unsigned_int_interval(unsigned int min, unsigned int max)
+{
+  unsigned int r, aux;
+  Frama_C_update_entropy();
+  aux = __fc_unsigned_int_entropy;
+  if (aux >= min && aux <= max)
     r = aux;
   else
     r = min;
   return r;
 }
 
-float Frama_C_float_interval(float min, float max)
+long Frama_C_long_interval(long min, long max)
 {
+  long r, aux;
   Frama_C_update_entropy();
-  return Frama_C_entropy_source ? min : max;
+  aux = __fc_long_entropy;
+  if (aux >= min && aux <= max)
+    r = aux;
+  else
+    r = min;
+  return r;
 }
 
-double Frama_C_double_interval(double min, double max)
+unsigned long Frama_C_unsigned_long_interval(unsigned long min, unsigned long max)
 {
+  unsigned long r, aux;
   Frama_C_update_entropy();
-  return Frama_C_entropy_source ? min : max;
+  aux = __fc_unsigned_long_entropy;
+  if (aux >= min && aux <= max)
+    r = aux;
+  else
+    r = min;
+  return r;
 }
 
 extern void __builtin_abort(void) __attribute__((noreturn)); // GCC builtin
diff --git a/share/libc/__fc_runtime.c b/share/libc/__fc_runtime.c
index 2c456c4d0378b7a74a7c19c357d7ded48aa02697..533b13ee312bb0397b6d75fbf7c2de9a49ec504a 100644
--- a/share/libc/__fc_runtime.c
+++ b/share/libc/__fc_runtime.c
@@ -33,6 +33,7 @@
 #include "math.c"
 #include "netdb.c"
 #include "netinet/in.c"
+#include "pwd.c"
 #include "signal.c"
 #include "stdatomic.c"
 #include "stdio.c"
diff --git a/share/libc/pwd.c b/share/libc/pwd.c
new file mode 100644
index 0000000000000000000000000000000000000000..624bc1f8409fe460412997bee3f1027b97aa34cd
--- /dev/null
+++ b/share/libc/pwd.c
@@ -0,0 +1,105 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of Frama-C.                                         */
+/*                                                                        */
+/*  Copyright (C) 2007-2022                                               */
+/*    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).            */
+/*                                                                        */
+/**************************************************************************/
+
+#include "__fc_builtin.h"
+#include "errno.h"
+#include "pwd.h"
+#include "string.h"
+
+__PUSH_FC_STDLIB
+
+char __fc_getpw_pw_name[64];
+char __fc_getpw_pw_passwd[64];
+char __fc_getpw_pw_gecos[64];
+char __fc_getpw_pw_dir[64];
+char __fc_getpw_pw_shell[64];
+
+static int __fc_getpw_init; // used to initialize the __fc_getpw* strings
+
+#define COPY_FIELD(fieldname)                   \
+  len = strlen(__fc_pwd.fieldname);             \
+  if (remaining <= len) {                       \
+    *result = NULL;                             \
+    return ERANGE;                              \
+  }                                             \
+  strcpy(buf, __fc_pwd.fieldname);              \
+  buf[len] = 0;                                 \
+  pwd->fieldname = buf;                         \
+  buf += len + 1;                               \
+  remaining -= len
+
+// Common code between getpwman_r and getpwuid_r
+static int __fc_getpw_r(struct passwd *pwd, char *buf,
+                        size_t buflen, struct passwd **result) {
+  // initialize global strings (only during first execution)
+  if (!__fc_getpw_init) {
+    __fc_getpw_init = 1;
+    Frama_C_make_unknown(__fc_getpw_pw_name, 63);
+    __fc_getpw_pw_name[63] = 0;
+    Frama_C_make_unknown(__fc_getpw_pw_passwd, 63);
+    __fc_getpw_pw_passwd[63] = 0;
+    Frama_C_make_unknown(__fc_getpw_pw_gecos, 63);
+    __fc_getpw_pw_gecos[63] = 0;
+    Frama_C_make_unknown(__fc_getpw_pw_dir, 63);
+    __fc_getpw_pw_dir[63] = 0;
+    Frama_C_make_unknown(__fc_getpw_pw_shell, 63);
+    __fc_getpw_pw_shell[63] = 0;
+  }
+
+  // simulate one of several possible errors, or "not found"
+  if (Frama_C_interval(0, 1)) {
+    // 'error or not found' case
+    *result = NULL;
+    if (Frama_C_interval(0, 1)) return EIO;
+    if (Frama_C_interval(0, 1)) return EMFILE;
+    if (Frama_C_interval(0, 1)) return ENFILE;
+    // Note: POSIX only specifies these values, but several implementations
+    // return others, including ENOENT, EBADF, ESRCH, EWOULDBLOCK, EPERM.
+    return 0;
+  } else {
+    // 'found without errors' case
+    size_t len, remaining = buflen;
+    // copy string fields to buf
+    COPY_FIELD(pw_name);
+    COPY_FIELD(pw_passwd);
+    COPY_FIELD(pw_gecos);
+    COPY_FIELD(pw_dir);
+    COPY_FIELD(pw_shell);
+    pwd->pw_uid = Frama_C_unsigned_int_interval(0, UINT_MAX);
+    pwd->pw_gid = Frama_C_unsigned_int_interval(0, UINT_MAX);
+    *result = pwd;
+    return 0;
+  }
+}
+
+int getpwnam_r(const char *name, struct passwd *pwd,
+               char *buf, size_t buflen, struct passwd **result) {
+  //@ assert valid_read_string(name);
+  return __fc_getpw_r(pwd, buf, buflen, result);
+}
+
+int getpwuid_r(uid_t uid, struct passwd *pwd,
+               char *buf, size_t buflen, struct passwd **result) {
+  return __fc_getpw_r(pwd, buf, buflen, result);
+}
+
+__POP_FC_STDLIB
diff --git a/share/libc/pwd.h b/share/libc/pwd.h
index fb9ddca482764743f31efef8d52ae07c97b5adda..5dfc799d95d6122af31d2486b840f5f1b6e6bc84 100644
--- a/share/libc/pwd.h
+++ b/share/libc/pwd.h
@@ -29,9 +29,9 @@ __PUSH_FC_STDLIB
 #include "__fc_define_uid_and_gid.h"
 #include "__fc_string_axiomatic.h"
 
+#include "errno.h"
 // for size_t
 #include "stddef.h"
-
 __BEGIN_DECLS
 
 struct passwd {
@@ -44,16 +44,18 @@ struct passwd {
   char    *pw_shell;
 };
 
-__FC_EXTERN char __fc_getpwuid_pw_name[64];
-__FC_EXTERN char __fc_getpwuid_pw_passwd[64];
-__FC_EXTERN char __fc_getpwuid_pw_dir[64];
-__FC_EXTERN char __fc_getpwuid_pw_shell[64];
+__FC_EXTERN char __fc_getpw_pw_name[64];
+__FC_EXTERN char __fc_getpw_pw_passwd[64];
+__FC_EXTERN char __fc_getpw_pw_gecos[64];
+__FC_EXTERN char __fc_getpw_pw_dir[64];
+__FC_EXTERN char __fc_getpw_pw_shell[64];
 
 struct passwd __fc_pwd =
-  {.pw_name = __fc_getpwuid_pw_name,
-   .pw_passwd = __fc_getpwuid_pw_passwd,
-   .pw_dir = __fc_getpwuid_pw_dir,
-   .pw_shell = __fc_getpwuid_pw_shell};
+  {.pw_name = __fc_getpw_pw_name,
+   .pw_passwd = __fc_getpw_pw_passwd,
+   .pw_gecos = __fc_getpw_pw_gecos,
+   .pw_dir = __fc_getpw_pw_dir,
+   .pw_shell = __fc_getpw_pw_shell};
 
 struct passwd *__fc_p_pwd = & __fc_pwd;
 
@@ -76,11 +78,41 @@ extern struct passwd *getpwnam(const char *name);
 */
 extern struct passwd *getpwuid(uid_t uid);
 
+/*@
+  // missing: assigns \result, *result, *pwd, __fc_pwd[0..] \from 'password database'
+  requires valid_name: valid_read_string(name);
+  requires valid_buf: \valid(buf+(0 .. buflen-1));
+  requires valid_pwd: \valid(pwd);
+  requires valid_result: \valid(result);
+  assigns \result \from indirect:__fc_p_pwd, indirect:name[0..];
+  assigns __fc_pwd \from indirect:name[0..];
+  assigns *pwd, *result \from __fc_p_pwd;
+  assigns buf[0 .. buflen-1] \from indirect:*__fc_p_pwd;
+  ensures result_null_or_assigned:
+    *result == \null || *result == pwd;
+  ensures result_ok_or_error:
+    \result == 0 || \result \in {EIO, EMFILE, ENFILE, ERANGE};
+*/
+extern int getpwnam_r(const char *name, struct passwd *pwd,
+                      char *buf, size_t buflen, struct passwd **result);
+
+/*@
+  // missing: assigns \result, *result, *pwd, __fc_pwd[0..] \from 'password database'
+  requires valid_buf: \valid(buf+(0 .. buflen-1));
+  requires valid_pwd: \valid(pwd);
+  requires valid_result: \valid(result);
+  assigns \result \from indirect:__fc_p_pwd;
+  assigns __fc_pwd \from indirect:uid;
+  assigns *pwd, *result \from __fc_p_pwd;
+  assigns buf[0 .. buflen-1] \from indirect:*__fc_p_pwd;
+  ensures result_null_or_assigned:
+    *result == \null || *result == pwd;
+  ensures result_ok_or_error:
+    \result == 0 || \result \in {EIO, EMFILE, ENFILE, ERANGE};
+*/
+extern int getpwuid_r(uid_t uid, struct passwd *pwd,
+                      char *buf, size_t buflen, struct passwd **result);
 
-extern int            getpwnam_r(const char *, struct passwd *, char *,
-			  size_t, struct passwd **);
-extern int            getpwuid_r(uid_t, struct passwd *, char *,
-			  size_t, struct passwd **);
 extern void           endpwent(void);
 extern struct passwd *getpwent(void);
 extern void           setpwent(void);
diff --git a/src/plugins/value/utils/library_functions.ml b/src/plugins/value/utils/library_functions.ml
index 51eee5493942a52e12279d33f5578f8ea2c689ab..31cc22262c686da14b52601fcb751379a012d83c 100644
--- a/src/plugins/value/utils/library_functions.ml
+++ b/src/plugins/value/utils/library_functions.ml
@@ -78,6 +78,8 @@ let unsupported_specifications =
     "getaddrinfo", "netdb.c";
     "getenv", "stdlib.c";
     "getline", "stdio.c";
+    "getpwnam_r", "pwd.c";
+    "getpwuid_r", "pwd.c";
     "glob", "glob.c";
     "globfree", "glob.c";
     "posix_memalign", "stdlib.c";
diff --git a/tests/libc/fc_builtin_c.c b/tests/libc/fc_builtin_c.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea336b1e04e74964ed8d1f4be98dbe91cc52e110
--- /dev/null
+++ b/tests/libc/fc_builtin_c.c
@@ -0,0 +1,37 @@
+#include "__fc_builtin.c"
+#include <limits.h>
+
+// The "sampling:unknown" assertions check whether a given value _may_ be
+// in the interval; they are supposed to return 'unknown', but never 'invalid'.
+
+int main() {
+  int i = Frama_C_interval(10, INT_MAX - 20);
+  //@ assert bounds: 10 <= i <= INT_MAX - 20;
+  //@ assert sampling:unknown: i == INT_MAX/2;
+
+  char c = Frama_C_char_interval(CHAR_MIN + 1, CHAR_MAX - 4);
+  //@ assert bounds: CHAR_MIN + 1 <= c <= CHAR_MAX - 4;
+  //@ assert sampling:unknown: c == 42;
+
+  unsigned int ui = Frama_C_unsigned_int_interval(INT_MAX, UINT_MAX);
+  //@ assert bounds: INT_MAX <= ui <= UINT_MAX;
+  //@ assert sampling:unknown: ui == UINT_MAX - 10000;
+
+  float f = Frama_C_float_interval(1.0, 2.0);
+  //@ assert bounds: 1.0 <= f <= 2.0;
+  //@ assert sampling:unknown: f == 1.5;
+
+  double one_e_100 = 0x1.249ad2594c37dp332;
+  double d = Frama_C_double_interval(1e10, one_e_100);
+  //@ assert bounds: 1e10 <= d <= one_e_100;
+  //@ assert sampling:unknown: d == 12345678901.2;
+
+  long l = Frama_C_long_interval(LONG_MIN, -2L);
+  //@ assert bounds: LONG_MIN <= l <= -2;
+  //@ assert sampling:unknown: l == -3;
+
+  unsigned long ul =
+    Frama_C_unsigned_long_interval(LONG_MAX - 1UL, LONG_MAX + 1UL);
+  //@ assert bounds: LONG_MAX - 1 <= ul <= LONG_MAX + 1;
+  //@ assert sampling:unknown: ul == LONG_MAX;
+}
diff --git a/tests/libc/fc_libc.c b/tests/libc/fc_libc.c
index f69e8856f26f206fb02669e031372919d735029e..8df9bf49c3366011cd6c9e3a700d0b59c9060c04 100644
--- a/tests/libc/fc_libc.c
+++ b/tests/libc/fc_libc.c
@@ -12,7 +12,7 @@
  MODULE: check_compliance
    OPT: -kernel-msg-key printer:attrs
  MODULE:
-   OPT: -load %{dep:@PTEST_NAME@.sav} -metrics -metrics-libc -then -lib-entry -metrics-no-libc | %{dep:./check_some_metrics.sh} "> 100" "> 400" "< 2" "> 20" "= 1" "= 1" "= 0" "= 0" "= 0" "= 1"
+   OPT: -load %{dep:@PTEST_NAME@.sav} -metrics -metrics-libc -then -lib-entry -metrics-no-libc | %{dep:./check_some_metrics.sh} "> 100" "> 400" "< 2" "> 0" "= 1" "= 1" "= 0" "= 0" "= 0" "= 1"
  CMD: %{dep:./check_full_libc.sh} @FRAMAC_SHARE@/libc
    OPT:
 **/
diff --git a/tests/libc/oracle/fc_builtin_c.res.oracle b/tests/libc/oracle/fc_builtin_c.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..d922ab4e1efacfb6929daebe1b0ce6160246ba19
--- /dev/null
+++ b/tests/libc/oracle/fc_builtin_c.res.oracle
@@ -0,0 +1,114 @@
+[kernel] Parsing fc_builtin_c.c (with preprocessing)
+[eva] Analyzing a complete application starting at main
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  
+[eva] computing for function Frama_C_interval <- main.
+  Called from fc_builtin_c.c:8.
+[eva] computing for function Frama_C_update_entropy <- Frama_C_interval <- main.
+  Called from FRAMAC_SHARE/libc/__fc_builtin.c:66.
+[eva] Recording results for Frama_C_update_entropy
+[eva] Done for function Frama_C_update_entropy
+[eva] Recording results for Frama_C_interval
+[eva] Done for function Frama_C_interval
+[eva] fc_builtin_c.c:9: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:10: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_char_interval <- main.
+  Called from fc_builtin_c.c:12.
+[eva] computing for function Frama_C_interval <- Frama_C_char_interval <- main.
+  Called from FRAMAC_SHARE/libc/__fc_builtin.c:77.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:66: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_interval
+[eva] Done for function Frama_C_interval
+[eva] Recording results for Frama_C_char_interval
+[eva] Done for function Frama_C_char_interval
+[eva] fc_builtin_c.c:13: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:14: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_unsigned_int_interval <- main.
+  Called from fc_builtin_c.c:16.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:100: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_unsigned_int_interval
+[eva] Done for function Frama_C_unsigned_int_interval
+[eva] fc_builtin_c.c:17: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:18: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_float_interval <- main.
+  Called from fc_builtin_c.c:20.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:82: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_float_interval
+[eva] Done for function Frama_C_float_interval
+[eva] fc_builtin_c.c:21: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:22: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_double_interval <- main.
+  Called from fc_builtin_c.c:25.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:88: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_double_interval
+[eva] Done for function Frama_C_double_interval
+[eva] fc_builtin_c.c:26: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:27: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_long_interval <- main.
+  Called from fc_builtin_c.c:29.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:112: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_long_interval
+[eva] Done for function Frama_C_long_interval
+[eva] fc_builtin_c.c:30: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:31: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] computing for function Frama_C_unsigned_long_interval <- main.
+  Called from fc_builtin_c.c:34.
+[eva] FRAMAC_SHARE/libc/__fc_builtin.c:124: 
+  Reusing old results for call to Frama_C_update_entropy
+[eva] Recording results for Frama_C_unsigned_long_interval
+[eva] Done for function Frama_C_unsigned_long_interval
+[eva] fc_builtin_c.c:35: assertion 'bounds' got status valid.
+[eva:alarm] fc_builtin_c.c:36: Warning: 
+  assertion 'sampling,unknown' got status unknown.
+[eva] Recording results for main
+[eva] done for function main
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function Frama_C_update_entropy:
+  Frama_C_entropy_source ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_double_interval:
+  Frama_C_entropy_source ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_float_interval:
+  Frama_C_entropy_source ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_interval:
+  Frama_C_entropy_source ∈ [--..--]
+  r ∈ [-127..2147483627]
+  aux ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_char_interval:
+  Frama_C_entropy_source ∈ [--..--]
+  __retres ∈ [-127..123]
+[eva:final-states] Values at end of function Frama_C_long_interval:
+  Frama_C_entropy_source ∈ [--..--]
+  r ∈ [-2147483648..-2]
+  aux ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_unsigned_int_interval:
+  Frama_C_entropy_source ∈ [--..--]
+  r ∈ [2147483647..4294967295]
+  aux ∈ [--..--]
+[eva:final-states] Values at end of function Frama_C_unsigned_long_interval:
+  Frama_C_entropy_source ∈ [--..--]
+  r ∈ {2147483646; 2147483647; 2147483648}
+  aux ∈ [--..--]
+[eva:final-states] Values at end of function main:
+  Frama_C_entropy_source ∈ [--..--]
+  i ∈ {1073741823}
+  c ∈ {42}
+  ui ∈ {4294957295}
+  f ∈ {1.5}
+  one_e_100 ∈ {1e+100}
+  d ∈ [12345678901.2 .. 12345678901.2]
+  l ∈ {-3}
+  ul ∈ {2147483647}
+  __retres ∈ {0}
diff --git a/tests/libc/oracle/fc_libc.0.res.oracle b/tests/libc/oracle/fc_libc.0.res.oracle
index 1309a406e2983d2ba843ca0103d55413f512e366..4cc020e5cf67e2cd14bf36a7352becb045d90275 100644
--- a/tests/libc/oracle/fc_libc.0.res.oracle
+++ b/tests/libc/oracle/fc_libc.0.res.oracle
@@ -55,6 +55,7 @@
 #include "netinet/in.h"
 #include "poll.h"
 #include "pthread.h"
+#include "pwd.c"
 #include "pwd.h"
 #include "setjmp.h"
 #include "signal.c"
diff --git a/tests/libc/oracle/fc_libc.1.res.oracle b/tests/libc/oracle/fc_libc.1.res.oracle
index 703535ed601a795d89b306eadc7e5bd34a338857..a2690ea17cec097b5479a970ea4c1346d1363a57 100644
--- a/tests/libc/oracle/fc_libc.1.res.oracle
+++ b/tests/libc/oracle/fc_libc.1.res.oracle
@@ -235,6 +235,15 @@ struct __fc_gethostbyname {
    char *host_aliases[2] ;
    char hostbuf[128] ;
 };
+struct passwd {
+   char *pw_name ;
+   char *pw_passwd ;
+   uid_t pw_uid ;
+   gid_t pw_gid ;
+   char *pw_gecos ;
+   char *pw_dir ;
+   char *pw_shell ;
+};
 typedef unsigned int ino_t;
 typedef long time_t;
 typedef unsigned int blkcnt_t;
@@ -340,15 +349,6 @@ struct pollfd {
    short revents ;
 };
 typedef unsigned long nfds_t;
-struct passwd {
-   char *pw_name ;
-   char *pw_passwd ;
-   uid_t pw_uid ;
-   gid_t pw_gid ;
-   char *pw_gecos ;
-   char *pw_dir ;
-   char *pw_shell ;
-};
 typedef int jmp_buf[5];
 struct __fc_sigjmp_buf {
    jmp_buf buf ;
@@ -417,14 +417,8 @@ int Frama_C_interval(int min, int max);
  */
 extern int Frama_C_interval_split(int min, int max);
 
-/*@ requires order: min ≤ max;
-    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
-    assigns \result, Frama_C_entropy_source;
-    assigns \result \from min, max, Frama_C_entropy_source;
-    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
- */
-extern unsigned char Frama_C_unsigned_char_interval(unsigned char min,
-                                                    unsigned char max);
+unsigned char Frama_C_unsigned_char_interval(unsigned char min,
+                                             unsigned char max);
 
 char Frama_C_char_interval(char min, char max);
 
@@ -445,14 +439,7 @@ extern unsigned short Frama_C_unsigned_short_interval(unsigned short min,
  */
 extern short Frama_C_short_interval(short min, short max);
 
-/*@ requires order: min ≤ max;
-    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
-    assigns \result, Frama_C_entropy_source;
-    assigns \result \from min, max, Frama_C_entropy_source;
-    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
- */
-extern unsigned int Frama_C_unsigned_int_interval(unsigned int min,
-                                                  unsigned int max);
+unsigned int Frama_C_unsigned_int_interval(unsigned int min, unsigned int max);
 
 /*@ requires order: min ≤ max;
     ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
@@ -462,22 +449,10 @@ extern unsigned int Frama_C_unsigned_int_interval(unsigned int min,
  */
 extern int Frama_C_int_interval(int min, int max);
 
-/*@ requires order: min ≤ max;
-    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
-    assigns \result, Frama_C_entropy_source;
-    assigns \result \from min, max, Frama_C_entropy_source;
-    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
- */
-extern unsigned long Frama_C_unsigned_long_interval(unsigned long min,
-                                                    unsigned long max);
+unsigned long Frama_C_unsigned_long_interval(unsigned long min,
+                                             unsigned long max);
 
-/*@ requires order: min ≤ max;
-    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
-    assigns \result, Frama_C_entropy_source;
-    assigns \result \from min, max, Frama_C_entropy_source;
-    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
- */
-extern long Frama_C_long_interval(long min, long max);
+long Frama_C_long_interval(long min, long max);
 
 /*@ requires order: min ≤ max;
     ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
@@ -537,6 +512,9 @@ extern long long Frama_C_abstract_max(long long i);
     assigns \result \from i; */
 extern long long Frama_C_abstract_min(long long i);
 
+unsigned int volatile __fc_unsigned_int_entropy;
+long volatile __fc_long_entropy;
+unsigned long volatile __fc_unsigned_long_entropy;
 /*@ assigns Frama_C_entropy_source;
     assigns Frama_C_entropy_source \from Frama_C_entropy_source;
  */
@@ -618,14 +596,9 @@ int Frama_C_interval(int min, int max)
 char Frama_C_char_interval(char min, char max)
 {
   char __retres;
-  int r;
-  char aux;
-  Frama_C_update_entropy();
-  aux = (char)Frama_C_entropy_source;
-  if ((int)aux >= (int)min) 
-    if ((int)aux <= (int)max) r = (int)aux; else r = (int)min;
-  else r = (int)min;
-  __retres = (char)r;
+  int tmp;
+  tmp = Frama_C_interval((int)min,(int)max);
+  __retres = (char)tmp;
   return __retres;
 }
 
@@ -663,6 +636,77 @@ double Frama_C_double_interval(double min, double max)
   return tmp;
 }
 
+/*@ requires order: min ≤ max;
+    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
+    assigns \result, Frama_C_entropy_source;
+    assigns \result \from min, max, Frama_C_entropy_source;
+    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
+ */
+unsigned char Frama_C_unsigned_char_interval(unsigned char min,
+                                             unsigned char max)
+{
+  unsigned char __retres;
+  int tmp;
+  tmp = Frama_C_interval((int)min,(int)max);
+  __retres = (unsigned char)tmp;
+  return __retres;
+}
+
+/*@ requires order: min ≤ max;
+    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
+    assigns \result, Frama_C_entropy_source;
+    assigns \result \from min, max, Frama_C_entropy_source;
+    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
+ */
+unsigned int Frama_C_unsigned_int_interval(unsigned int min, unsigned int max)
+{
+  unsigned int r;
+  unsigned int aux;
+  Frama_C_update_entropy();
+  aux = __fc_unsigned_int_entropy;
+  if (aux >= min) 
+    if (aux <= max) r = aux; else r = min;
+  else r = min;
+  return r;
+}
+
+/*@ requires order: min ≤ max;
+    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
+    assigns \result, Frama_C_entropy_source;
+    assigns \result \from min, max, Frama_C_entropy_source;
+    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
+ */
+long Frama_C_long_interval(long min, long max)
+{
+  long r;
+  long aux;
+  Frama_C_update_entropy();
+  aux = __fc_long_entropy;
+  if (aux >= min) 
+    if (aux <= max) r = aux; else r = min;
+  else r = min;
+  return r;
+}
+
+/*@ requires order: min ≤ max;
+    ensures result_bounded: \old(min) ≤ \result ≤ \old(max);
+    assigns \result, Frama_C_entropy_source;
+    assigns \result \from min, max, Frama_C_entropy_source;
+    assigns Frama_C_entropy_source \from Frama_C_entropy_source;
+ */
+unsigned long Frama_C_unsigned_long_interval(unsigned long min,
+                                             unsigned long max)
+{
+  unsigned long r;
+  unsigned long aux;
+  Frama_C_update_entropy();
+  aux = __fc_unsigned_long_entropy;
+  if (aux >= min) 
+    if (aux <= max) r = aux; else r = min;
+  else r = min;
+  return r;
+}
+
 extern  __attribute__((__noreturn__)) void __builtin_abort(void);
 
 /*@ terminates \false;
@@ -5218,6 +5262,204 @@ struct in6_addr const in6addr_loopback =
                (unsigned char)0,
                (unsigned char)0,
                (unsigned char)1}};
+char __fc_getpw_pw_name[64];
+char __fc_getpw_pw_passwd[64];
+char __fc_getpw_pw_gecos[64];
+char __fc_getpw_pw_dir[64];
+char __fc_getpw_pw_shell[64];
+struct passwd __fc_pwd =
+  {.pw_name = __fc_getpw_pw_name,
+   .pw_passwd = __fc_getpw_pw_passwd,
+   .pw_uid = 0U,
+   .pw_gid = 0U,
+   .pw_gecos = __fc_getpw_pw_gecos,
+   .pw_dir = __fc_getpw_pw_dir,
+   .pw_shell = __fc_getpw_pw_shell};
+struct passwd *__fc_p_pwd = & __fc_pwd;
+/*@ requires valid_name: valid_read_string(name);
+    ensures
+      result_null_or_internal_struct:
+        \result ≡ \null ∨ \result ≡ __fc_p_pwd;
+    assigns \result, __fc_pwd;
+    assigns \result \from __fc_p_pwd, (indirect: *(name + (0 ..)));
+    assigns __fc_pwd \from (indirect: *(name + (0 ..)));
+ */
+extern struct passwd *getpwnam(char const *name);
+
+/*@ ensures
+      result_null_or_internal_struct:
+        \result ≡ \null ∨ \result ≡ __fc_p_pwd;
+    assigns \result, __fc_pwd;
+    assigns \result \from __fc_p_pwd, (indirect: uid);
+    assigns __fc_pwd \from (indirect: uid);
+ */
+extern struct passwd *getpwuid(uid_t uid);
+
+int getpwnam_r(char const *name, struct passwd *pwd, char *buf,
+               size_t buflen, struct passwd **result);
+
+int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen,
+               struct passwd **result);
+
+static int __fc_getpw_init;
+static int __fc_getpw_r(struct passwd *pwd, char *buf, size_t buflen,
+                        struct passwd **result)
+{
+  int __retres;
+  int tmp_2;
+  if (! __fc_getpw_init) {
+    __fc_getpw_init = 1;
+    Frama_C_make_unknown(__fc_getpw_pw_name,(unsigned int)63);
+    __fc_getpw_pw_name[63] = (char)0;
+    Frama_C_make_unknown(__fc_getpw_pw_passwd,(unsigned int)63);
+    __fc_getpw_pw_passwd[63] = (char)0;
+    Frama_C_make_unknown(__fc_getpw_pw_gecos,(unsigned int)63);
+    __fc_getpw_pw_gecos[63] = (char)0;
+    Frama_C_make_unknown(__fc_getpw_pw_dir,(unsigned int)63);
+    __fc_getpw_pw_dir[63] = (char)0;
+    Frama_C_make_unknown(__fc_getpw_pw_shell,(unsigned int)63);
+    __fc_getpw_pw_shell[63] = (char)0;
+  }
+  tmp_2 = Frama_C_interval(0,1);
+  if (tmp_2) {
+    int tmp;
+    int tmp_0;
+    int tmp_1;
+    *result = (struct passwd *)0;
+    tmp = Frama_C_interval(0,1);
+    if (tmp) {
+      __retres = 5;
+      goto return_label;
+    }
+    tmp_0 = Frama_C_interval(0,1);
+    if (tmp_0) {
+      __retres = 24;
+      goto return_label;
+    }
+    tmp_1 = Frama_C_interval(0,1);
+    if (tmp_1) {
+      __retres = 23;
+      goto return_label;
+    }
+    __retres = 0;
+    goto return_label;
+  }
+  else {
+    size_t len;
+    size_t remaining = buflen;
+    len = strlen((char const *)__fc_pwd.pw_name);
+    if (remaining <= len) {
+      *result = (struct passwd *)0;
+      __retres = 34;
+      goto return_label;
+    }
+    strcpy(buf,(char const *)__fc_pwd.pw_name);
+    *(buf + len) = (char)0;
+    pwd->pw_name = buf;
+    buf += len + (size_t)1;
+    remaining -= len;
+    len = strlen((char const *)__fc_pwd.pw_passwd);
+    if (remaining <= len) {
+      *result = (struct passwd *)0;
+      __retres = 34;
+      goto return_label;
+    }
+    strcpy(buf,(char const *)__fc_pwd.pw_passwd);
+    *(buf + len) = (char)0;
+    pwd->pw_passwd = buf;
+    buf += len + (size_t)1;
+    remaining -= len;
+    len = strlen((char const *)__fc_pwd.pw_gecos);
+    if (remaining <= len) {
+      *result = (struct passwd *)0;
+      __retres = 34;
+      goto return_label;
+    }
+    strcpy(buf,(char const *)__fc_pwd.pw_gecos);
+    *(buf + len) = (char)0;
+    pwd->pw_gecos = buf;
+    buf += len + (size_t)1;
+    remaining -= len;
+    len = strlen((char const *)__fc_pwd.pw_dir);
+    if (remaining <= len) {
+      *result = (struct passwd *)0;
+      __retres = 34;
+      goto return_label;
+    }
+    strcpy(buf,(char const *)__fc_pwd.pw_dir);
+    *(buf + len) = (char)0;
+    pwd->pw_dir = buf;
+    buf += len + (size_t)1;
+    remaining -= len;
+    len = strlen((char const *)__fc_pwd.pw_shell);
+    if (remaining <= len) {
+      *result = (struct passwd *)0;
+      __retres = 34;
+      goto return_label;
+    }
+    strcpy(buf,(char const *)__fc_pwd.pw_shell);
+    *(buf + len) = (char)0;
+    pwd->pw_shell = buf;
+    buf += len + (size_t)1;
+    remaining -= len;
+    pwd->pw_uid = Frama_C_unsigned_int_interval((unsigned int)0,4294967295U);
+    pwd->pw_gid = Frama_C_unsigned_int_interval((unsigned int)0,4294967295U);
+    *result = pwd;
+    __retres = 0;
+    goto return_label;
+  }
+  return_label: return __retres;
+}
+
+/*@ requires valid_name: valid_read_string(name);
+    requires valid_buf: \valid(buf + (0 .. buflen - 1));
+    requires valid_pwd: \valid(pwd);
+    requires valid_result: \valid(result);
+    ensures
+      result_null_or_assigned:
+        *\old(result) ≡ \null ∨ *\old(result) ≡ \old(pwd);
+    ensures
+      result_ok_or_error: \result ≡ 0 ∨ \result ∈ {5, 24, 23, 34};
+    assigns \result, __fc_pwd, *pwd, *result, *(buf + (0 .. buflen - 1));
+    assigns \result
+      \from (indirect: __fc_p_pwd), (indirect: *(name + (0 ..)));
+    assigns __fc_pwd \from (indirect: *(name + (0 ..)));
+    assigns *pwd \from __fc_p_pwd;
+    assigns *result \from __fc_p_pwd;
+    assigns *(buf + (0 .. buflen - 1)) \from (indirect: *__fc_p_pwd);
+ */
+int getpwnam_r(char const *name, struct passwd *pwd, char *buf,
+               size_t buflen, struct passwd **result)
+{
+  int tmp;
+  /*@ assert valid_read_string(name); */ ;
+  tmp = __fc_getpw_r(pwd,buf,buflen,result);
+  return tmp;
+}
+
+/*@ requires valid_buf: \valid(buf + (0 .. buflen - 1));
+    requires valid_pwd: \valid(pwd);
+    requires valid_result: \valid(result);
+    ensures
+      result_null_or_assigned:
+        *\old(result) ≡ \null ∨ *\old(result) ≡ \old(pwd);
+    ensures
+      result_ok_or_error: \result ≡ 0 ∨ \result ∈ {5, 24, 23, 34};
+    assigns \result, __fc_pwd, *pwd, *result, *(buf + (0 .. buflen - 1));
+    assigns \result \from (indirect: __fc_p_pwd);
+    assigns __fc_pwd \from (indirect: uid);
+    assigns *pwd \from __fc_p_pwd;
+    assigns *result \from __fc_p_pwd;
+    assigns *(buf + (0 .. buflen - 1)) \from (indirect: *__fc_p_pwd);
+ */
+int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen,
+               struct passwd **result)
+{
+  int tmp;
+  tmp = __fc_getpw_r(pwd,buf,buflen,result);
+  return tmp;
+}
+
 /*@ ghost unsigned int volatile __fc_time; */
 /*@ assigns \result;
     assigns \result \from __fc_time; */
@@ -9310,42 +9552,6 @@ int pthread_setname_np(pthread_t thread, char const *name);
  */
 int pthread_getname_np(pthread_t thread, char *name, size_t len);
 
-extern char __fc_getpwuid_pw_name[64];
-
-extern char __fc_getpwuid_pw_passwd[64];
-
-extern char __fc_getpwuid_pw_dir[64];
-
-extern char __fc_getpwuid_pw_shell[64];
-
-struct passwd __fc_pwd =
-  {.pw_name = __fc_getpwuid_pw_name,
-   .pw_passwd = __fc_getpwuid_pw_passwd,
-   .pw_uid = 0U,
-   .pw_gid = 0U,
-   .pw_gecos = (char *)0,
-   .pw_dir = __fc_getpwuid_pw_dir,
-   .pw_shell = __fc_getpwuid_pw_shell};
-struct passwd *__fc_p_pwd = & __fc_pwd;
-/*@ requires valid_name: valid_read_string(name);
-    ensures
-      result_null_or_internal_struct:
-        \result ≡ \null ∨ \result ≡ __fc_p_pwd;
-    assigns \result, __fc_pwd;
-    assigns \result \from __fc_p_pwd, (indirect: *(name + (0 ..)));
-    assigns __fc_pwd \from (indirect: *(name + (0 ..)));
- */
-extern struct passwd *getpwnam(char const *name);
-
-/*@ ensures
-      result_null_or_internal_struct:
-        \result ≡ \null ∨ \result ≡ __fc_p_pwd;
-    assigns \result, __fc_pwd;
-    assigns \result \from __fc_p_pwd, (indirect: uid);
-    assigns __fc_pwd \from (indirect: uid);
- */
-extern struct passwd *getpwuid(uid_t uid);
-
 /*@ assigns *(env + (0 .. 4)); */
 extern int setjmp(int env[5]);
 
diff --git a/tests/libc/oracle/pwd_c.res.oracle b/tests/libc/oracle/pwd_c.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..d2523bf304f3c2609e99a6d4a229739525eacf22
--- /dev/null
+++ b/tests/libc/oracle/pwd_c.res.oracle
@@ -0,0 +1,314 @@
+[kernel] Parsing pwd_c.c (with preprocessing)
+[eva] Option -eva-precision 1 detected, automatic configuration of the analysis:
+  option -eva-min-loop-unroll set to 0 (default value).
+  option -eva-auto-loop-unroll set to 16.
+  option -eva-widening-delay set to 1.
+  option -eva-partition-history set to 0 (default value).
+  option -eva-slevel set to 10.
+  option -eva-ilevel set to 12.
+  option -eva-plevel set to 20.
+  option -eva-subdivide-non-linear set to 20.
+  option -eva-remove-redundant-alarms set to true (default value).
+  option -eva-domains set to 'cvalue,symbolic-locations'.
+  option -eva-split-return already set to 'full' (not modified).
+  option -eva-equality-through-calls set to 'none'.
+  option -eva-octagon-through-calls set to false (default value).
+[eva] Splitting return states on:
+  \full_split(@all)
+[eva] Analyzing a complete application starting at main
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  uid ∈ [--..--]
+[eva] computing for function getpwuid_r <- main.
+  Called from pwd_c.c:14.
+[eva] computing for function __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:102.
+[eva] computing for function Frama_C_make_unknown <- __fc_getpw_r <- getpwuid_r <- 
+                          main.
+  Called from FRAMAC_SHARE/libc/pwd.c:56.
+[eva] using specification for function Frama_C_make_unknown
+[eva] FRAMAC_SHARE/libc/pwd.c:56: 
+  function Frama_C_make_unknown: precondition 'valid_p' got status valid.
+[eva] Done for function Frama_C_make_unknown
+[eva] computing for function Frama_C_make_unknown <- __fc_getpw_r <- getpwuid_r <- 
+                          main.
+  Called from FRAMAC_SHARE/libc/pwd.c:58.
+[eva] FRAMAC_SHARE/libc/pwd.c:58: 
+  function Frama_C_make_unknown: precondition 'valid_p' got status valid.
+[eva] Done for function Frama_C_make_unknown
+[eva] computing for function Frama_C_make_unknown <- __fc_getpw_r <- getpwuid_r <- 
+                          main.
+  Called from FRAMAC_SHARE/libc/pwd.c:60.
+[eva] FRAMAC_SHARE/libc/pwd.c:60: 
+  function Frama_C_make_unknown: precondition 'valid_p' got status valid.
+[eva] Done for function Frama_C_make_unknown
+[eva] computing for function Frama_C_make_unknown <- __fc_getpw_r <- getpwuid_r <- 
+                          main.
+  Called from FRAMAC_SHARE/libc/pwd.c:62.
+[eva] FRAMAC_SHARE/libc/pwd.c:62: 
+  function Frama_C_make_unknown: precondition 'valid_p' got status valid.
+[eva] Done for function Frama_C_make_unknown
+[eva] computing for function Frama_C_make_unknown <- __fc_getpw_r <- getpwuid_r <- 
+                          main.
+  Called from FRAMAC_SHARE/libc/pwd.c:64.
+[eva] FRAMAC_SHARE/libc/pwd.c:64: 
+  function Frama_C_make_unknown: precondition 'valid_p' got status valid.
+[eva] Done for function Frama_C_make_unknown
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:69.
+[eva] using specification for function Frama_C_interval
+[eva] FRAMAC_SHARE/libc/pwd.c:69: 
+  function Frama_C_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:72.
+[eva] FRAMAC_SHARE/libc/pwd.c:72: 
+  function Frama_C_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:73.
+[eva] FRAMAC_SHARE/libc/pwd.c:73: 
+  function Frama_C_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:74.
+[eva] FRAMAC_SHARE/libc/pwd.c:74: 
+  function Frama_C_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_interval
+[eva] FRAMAC_SHARE/libc/pwd.c:82: Call to builtin strlen
+[eva] FRAMAC_SHARE/libc/pwd.c:82: 
+  function strlen: precondition 'valid_string_s' got status valid.
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:82.
+[eva] using specification for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:82: 
+  function strcpy: precondition 'valid_string_src' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:82: 
+  function strcpy: precondition 'room_string' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:82: 
+  function strcpy: precondition 'separation' got status valid.
+[eva] FRAMAC_SHARE/libc/string.h:373: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function strcmp
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:83: Call to builtin strlen
+[eva] FRAMAC_SHARE/libc/pwd.c:83: 
+  function strlen: precondition 'valid_string_s' got status valid.
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:83.
+[eva] FRAMAC_SHARE/libc/pwd.c:83: 
+  function strcpy: precondition 'valid_string_src' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:83: 
+  function strcpy: precondition 'room_string' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:83: 
+  function strcpy: precondition 'separation' got status valid.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:84: Call to builtin strlen
+[eva] FRAMAC_SHARE/libc/pwd.c:84: 
+  function strlen: precondition 'valid_string_s' got status valid.
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:84.
+[eva] FRAMAC_SHARE/libc/pwd.c:84: 
+  function strcpy: precondition 'valid_string_src' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:84: 
+  function strcpy: precondition 'room_string' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:84: 
+  function strcpy: precondition 'separation' got status valid.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:85: Call to builtin strlen
+[eva] FRAMAC_SHARE/libc/pwd.c:85: 
+  function strlen: precondition 'valid_string_s' got status valid.
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:85.
+[eva] FRAMAC_SHARE/libc/pwd.c:85: 
+  function strcpy: precondition 'valid_string_src' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:85: 
+  function strcpy: precondition 'room_string' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:85: 
+  function strcpy: precondition 'separation' got status valid.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:86: Call to builtin strlen
+[eva] FRAMAC_SHARE/libc/pwd.c:86: 
+  function strlen: precondition 'valid_string_s' got status valid.
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:86.
+[eva] FRAMAC_SHARE/libc/pwd.c:86: 
+  function strcpy: precondition 'valid_string_src' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:86: 
+  function strcpy: precondition 'room_string' got status valid.
+[eva] FRAMAC_SHARE/libc/pwd.c:86: 
+  function strcpy: precondition 'separation' got status valid.
+[eva] Done for function strcpy
+[eva] computing for function Frama_C_unsigned_int_interval <- __fc_getpw_r <- 
+                          getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:87.
+[eva] using specification for function Frama_C_unsigned_int_interval
+[eva] FRAMAC_SHARE/libc/pwd.c:87: 
+  function Frama_C_unsigned_int_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_unsigned_int_interval
+[eva] computing for function Frama_C_unsigned_int_interval <- __fc_getpw_r <- 
+                          getpwuid_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:88.
+[eva] FRAMAC_SHARE/libc/pwd.c:88: 
+  function Frama_C_unsigned_int_interval: precondition 'order' got status valid.
+[eva] Done for function Frama_C_unsigned_int_interval
+[eva] Recording results for __fc_getpw_r
+[eva] Done for function __fc_getpw_r
+[eva] Recording results for getpwuid_r
+[eva] Done for function getpwuid_r
+[eva] pwd_c.c:16: assertion got status valid.
+[eva] pwd_c.c:17: assertion got status valid.
+[eva] pwd_c.c:18: assertion got status valid.
+[eva:alarm] pwd_c.c:20: Warning: assertion got status unknown.
+[eva:alarm] pwd_c.c:21: Warning: assertion got status unknown.
+[eva:alarm] pwd_c.c:22: Warning: assertion got status unknown.
+[eva:alarm] pwd_c.c:23: Warning: assertion got status unknown.
+[eva] computing for function getpwnam_r <- main.
+  Called from pwd_c.c:27.
+[eva] FRAMAC_SHARE/libc/pwd.c:96: assertion got status valid.
+[eva] computing for function __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:97.
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:69.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:72.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:73.
+[eva] Done for function Frama_C_interval
+[eva] computing for function Frama_C_interval <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:74.
+[eva] Done for function Frama_C_interval
+[eva] FRAMAC_SHARE/libc/pwd.c:82: Call to builtin strlen
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:82.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:83: Call to builtin strlen
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:83.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:84: Call to builtin strlen
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:84.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:85: Call to builtin strlen
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:85.
+[eva] Done for function strcpy
+[eva] FRAMAC_SHARE/libc/pwd.c:86: Call to builtin strlen
+[eva] computing for function strcpy <- __fc_getpw_r <- getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:86.
+[eva] Done for function strcpy
+[eva] computing for function Frama_C_unsigned_int_interval <- __fc_getpw_r <- 
+                          getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:87.
+[eva] Done for function Frama_C_unsigned_int_interval
+[eva] computing for function Frama_C_unsigned_int_interval <- __fc_getpw_r <- 
+                          getpwnam_r <- main.
+  Called from FRAMAC_SHARE/libc/pwd.c:88.
+[eva] Done for function Frama_C_unsigned_int_interval
+[eva] Recording results for __fc_getpw_r
+[eva] Done for function __fc_getpw_r
+[eva] Recording results for getpwnam_r
+[eva] Done for function getpwnam_r
+[eva] pwd_c.c:29: assertion got status valid.
+[eva] pwd_c.c:30: assertion got status valid.
+[eva] pwd_c.c:31: assertion got status valid.
+[eva:alarm] pwd_c.c:33: Warning: assertion 'unknown_for_now' got status unknown.
+[eva:alarm] pwd_c.c:34: Warning: assertion 'unknown_for_now' got status unknown.
+[eva:alarm] pwd_c.c:35: Warning: assertion 'unknown_for_now' got status unknown.
+[eva:alarm] pwd_c.c:36: Warning: assertion 'unknown_for_now' got status unknown.
+[eva] Recording results for main
+[eva] done for function main
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function __fc_getpw_r:
+  Frama_C_entropy_source ∈ [--..--]
+  __fc_getpw_pw_name[0..62] ∈ [--..--]
+                    [63] ∈ {0}
+  __fc_getpw_pw_passwd[0..62] ∈ [--..--]
+                      [63] ∈ {0}
+  __fc_getpw_pw_gecos[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  __fc_getpw_pw_dir[0..62] ∈ [--..--]
+                   [63] ∈ {0}
+  __fc_getpw_pw_shell[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  buf ∈ {{ &buf + [0..320] }}
+  pwd_out.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+         .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+         {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+         .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+         .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+         .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+  result ∈ {{ NULL ; &pwd_out ; &pwd_out2 }}
+  buf[0..319] ∈ [--..--] or UNINITIALIZED
+  pwd_out2.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+          .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+          {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+          .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+          .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+          .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+  __fc_getpw_init ∈ {1}
+  __retres ∈ {0; 5; 23; 24}
+[eva:final-states] Values at end of function getpwnam_r:
+  Frama_C_entropy_source ∈ [--..--]
+  result ∈ {{ NULL ; &pwd_out2 }}
+  buf[0..319] ∈ [--..--] or UNINITIALIZED
+  pwd_out2.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+          .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+          {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+          .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+          .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+          .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+[eva:final-states] Values at end of function getpwuid_r:
+  Frama_C_entropy_source ∈ [--..--]
+  __fc_getpw_pw_name[0..62] ∈ [--..--]
+                    [63] ∈ {0}
+  __fc_getpw_pw_passwd[0..62] ∈ [--..--]
+                      [63] ∈ {0}
+  __fc_getpw_pw_gecos[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  __fc_getpw_pw_dir[0..62] ∈ [--..--]
+                   [63] ∈ {0}
+  __fc_getpw_pw_shell[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  pwd_out.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+         .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+         {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+         .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+         .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+         .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+  result ∈ {{ NULL ; &pwd_out }}
+  buf[0..319] ∈ [--..--] or UNINITIALIZED
+  __fc_getpw_init ∈ {1}
+[eva:final-states] Values at end of function main:
+  Frama_C_entropy_source ∈ [--..--]
+  __fc_getpw_pw_name[0..62] ∈ [--..--]
+                    [63] ∈ {0}
+  __fc_getpw_pw_passwd[0..62] ∈ [--..--]
+                      [63] ∈ {0}
+  __fc_getpw_pw_gecos[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  __fc_getpw_pw_dir[0..62] ∈ [--..--]
+                   [63] ∈ {0}
+  __fc_getpw_pw_shell[0..62] ∈ [--..--]
+                     [63] ∈ {0}
+  pwd_out.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+         .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+         {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+         .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+         .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+         .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+  result ∈ {{ NULL ; &pwd_out2 }}
+  buf[0..319] ∈ [--..--] or UNINITIALIZED
+  buflen ∈ {320}
+  res ∈ {0; 5; 23; 24}
+  pwd_out2.pw_name ∈ {{ &buf[0] }} or UNINITIALIZED
+          .pw_passwd ∈ {{ &buf + [1..64] }} or UNINITIALIZED
+          {.pw_uid; .pw_gid} ∈ [--..--] or UNINITIALIZED
+          .pw_gecos ∈ {{ &buf + [2..128] }} or UNINITIALIZED
+          .pw_dir ∈ {{ &buf + [3..192] }} or UNINITIALIZED
+          .pw_shell ∈ {{ &buf + [4..256] }} or UNINITIALIZED
+  __fc_getpw_init ∈ {1}
+  __retres ∈ {0}
diff --git a/tests/libc/oracle/pwd_h.res.oracle b/tests/libc/oracle/pwd_h.res.oracle
index 9d329cca5b9c2c7685cd8b3e2cacecfdec83c97e..1ef5e0ebc0b91745bbe4736f93732c39357f5158 100644
--- a/tests/libc/oracle/pwd_h.res.oracle
+++ b/tests/libc/oracle/pwd_h.res.oracle
@@ -25,10 +25,11 @@
 [eva] done for function main
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
-  __fc_pwd.pw_name ∈ {{ NULL + [--..--] ; &__fc_getpwuid_pw_name[0] }}
-          .pw_passwd ∈ {{ NULL + [--..--] ; &__fc_getpwuid_pw_passwd[0] }}
-          {.pw_uid; .pw_gid; .pw_gecos} ∈ [--..--]
-          .pw_dir ∈ {{ NULL + [--..--] ; &__fc_getpwuid_pw_dir[0] }}
-          .pw_shell ∈ {{ NULL + [--..--] ; &__fc_getpwuid_pw_shell[0] }}
+  __fc_pwd.pw_name ∈ {{ NULL + [--..--] ; &__fc_getpw_pw_name[0] }}
+          .pw_passwd ∈ {{ NULL + [--..--] ; &__fc_getpw_pw_passwd[0] }}
+          {.pw_uid; .pw_gid} ∈ [--..--]
+          .pw_gecos ∈ {{ NULL + [--..--] ; &__fc_getpw_pw_gecos[0] }}
+          .pw_dir ∈ {{ NULL + [--..--] ; &__fc_getpw_pw_dir[0] }}
+          .pw_shell ∈ {{ NULL + [--..--] ; &__fc_getpw_pw_shell[0] }}
   pw ∈ {{ NULL ; &__fc_pwd }}
   __retres ∈ {0}
diff --git a/tests/libc/pwd_c.c b/tests/libc/pwd_c.c
new file mode 100644
index 0000000000000000000000000000000000000000..d60731f7f1083760b046905442bf96b156a62413
--- /dev/null
+++ b/tests/libc/pwd_c.c
@@ -0,0 +1,38 @@
+/*run.config
+  STDOPT: #"-eva-precision 1 -eva-split-return full"
+*/
+#include "pwd.c"
+#include "__fc_string_axiomatic.h"
+
+extern uid_t uid;
+
+int main() {
+  struct passwd pwd_out;
+  struct passwd *result;
+  char buf[320];
+  size_t buflen = sizeof(buf);
+  int res = getpwuid_r(uid, &pwd_out, buf, buflen, &result);
+  if (result) {
+    //@ assert res == 0;
+    //@ assert \initialized(&pwd_out.pw_uid);
+    //@ assert \initialized(&pwd_out.pw_gid);
+    //Note: ideally, the following assertions will be 'true' someday
+    //@ assert valid_read_string(pwd_out.pw_name);
+    //@ assert valid_read_string(pwd_out.pw_passwd);
+    //@ assert valid_read_string(pwd_out.pw_dir);
+    //@ assert valid_read_string(pwd_out.pw_shell);
+  }
+  //@ slevel merge;
+  struct passwd pwd_out2;
+  res = getpwnam_r("root", &pwd_out2, buf, buflen, &result);
+  if (result) {
+    //@ assert res == 0;
+    //@ assert \initialized(&pwd_out2.pw_uid);
+    //@ assert \initialized(&pwd_out2.pw_gid);
+    //Note: ideally, the following assertions will be 'true' someday
+    //@ assert unknown_for_now: valid_read_string(pwd_out2.pw_name);
+    //@ assert unknown_for_now: valid_read_string(pwd_out2.pw_passwd);
+    //@ assert unknown_for_now: valid_read_string(pwd_out2.pw_dir);
+    //@ assert unknown_for_now: valid_read_string(pwd_out2.pw_shell);
+  }
+}