From 1e6f913593d3a32584f721e1a0441cf96b845eb7 Mon Sep 17 00:00:00 2001
From: Andre Maroneze <andre.maroneze@cea.fr>
Date: Thu, 21 Mar 2024 11:27:22 +0100
Subject: [PATCH] [Libc] add __FC_PTHREAD_T_IS_SCALAR to handle non-portable
 code

---
 share/libc/__fc_define_pthread_types.h        |  7 ++
 ...ad_h.res.oracle => pthread_h.0.res.oracle} | 52 +++++-----
 tests/libc/oracle/pthread_h.1.res.oracle      | 94 +++++++++++++++++++
 tests/libc/oracle/pthread_h.2.res.oracle      | 10 ++
 tests/libc/pthread_h.c                        | 14 +++
 5 files changed, 151 insertions(+), 26 deletions(-)
 rename tests/libc/oracle/{pthread_h.res.oracle => pthread_h.0.res.oracle} (79%)
 create mode 100644 tests/libc/oracle/pthread_h.1.res.oracle
 create mode 100644 tests/libc/oracle/pthread_h.2.res.oracle

diff --git a/share/libc/__fc_define_pthread_types.h b/share/libc/__fc_define_pthread_types.h
index 391d2ae3a1a..d7be74b4d9d 100644
--- a/share/libc/__fc_define_pthread_types.h
+++ b/share/libc/__fc_define_pthread_types.h
@@ -44,7 +44,14 @@ typedef struct __fc_pthread_once_t { int _fc; } pthread_once_t;
 typedef struct __fc_pthread_rwlock_t { int _fc; } pthread_rwlock_t;
 typedef struct __fc_pthread_rwlockattr_t { int _fc; } pthread_rwlockattr_t;
 typedef struct __fc_pthread_spinlock_t { int _fc; } pthread_spinlock_t;
+
+#ifdef __FC_PTHREAD_T_IS_SCALAR
+// Some non-portable code assumes pthread_t as a scalar; this allows
+// such code to be parsed.
+typedef unsigned long pthread_t;
+#else
 typedef struct __fc_pthread_t { int _fc; } pthread_t;
+#endif
 __END_DECLS
 __POP_FC_STDLIB
 #endif
diff --git a/tests/libc/oracle/pthread_h.res.oracle b/tests/libc/oracle/pthread_h.0.res.oracle
similarity index 79%
rename from tests/libc/oracle/pthread_h.res.oracle
rename to tests/libc/oracle/pthread_h.0.res.oracle
index 6511a6631d2..41d84474ca4 100644
--- a/tests/libc/oracle/pthread_h.res.oracle
+++ b/tests/libc/oracle/pthread_h.0.res.oracle
@@ -6,73 +6,73 @@
   retval ∈ {0}
   v ∈ [--..--]
 [eva] computing for function pthread_create <- main.
-  Called from pthread_h.c:17.
+  Called from pthread_h.c:23.
 [eva] using specification for function pthread_create
-[eva] pthread_h.c:17: 
+[eva] pthread_h.c:23: 
   function pthread_create: precondition 'valid_thread' got status valid.
-[eva] pthread_h.c:17: 
+[eva] pthread_h.c:23: 
   function pthread_create: precondition 'valid_null_attr' got status valid.
-[eva] pthread_h.c:17: 
+[eva] pthread_h.c:23: 
   function pthread_create: precondition 'valid_routine' got status valid.
-[eva] pthread_h.c:17: 
+[eva] pthread_h.c:23: 
   function pthread_create: precondition 'valid_null_arg' got status valid.
 [eva] Done for function pthread_create
 [eva] computing for function printf_va_2 <- main.
-  Called from pthread_h.c:19.
+  Called from pthread_h.c:25.
 [eva] using specification for function printf_va_2
-[eva] pthread_h.c:19: function printf_va_2: precondition got status valid.
+[eva] pthread_h.c:25: function printf_va_2: precondition got status valid.
 [eva] Done for function printf_va_2
 [eva] computing for function printf_va_3 <- main.
-  Called from pthread_h.c:22.
+  Called from pthread_h.c:28.
 [eva] using specification for function printf_va_3
-[eva] pthread_h.c:22: function printf_va_3: precondition got status valid.
+[eva] pthread_h.c:28: function printf_va_3: precondition got status valid.
 [eva] Done for function printf_va_3
 [eva] computing for function pthread_setname_np <- main.
-  Called from pthread_h.c:23.
+  Called from pthread_h.c:29.
 [eva] using specification for function pthread_setname_np
-[eva] pthread_h.c:23: 
+[eva] pthread_h.c:29: 
   function pthread_setname_np: precondition 'valid_name' got status valid.
 [eva] Done for function pthread_setname_np
 [eva] computing for function pthread_getname_np <- main.
-  Called from pthread_h.c:26.
+  Called from pthread_h.c:32.
 [eva] using specification for function pthread_getname_np
-[eva] pthread_h.c:26: 
+[eva] pthread_h.c:32: 
   function pthread_getname_np: precondition 'valid_name' got status valid.
 [eva] Done for function pthread_getname_np
 [eva] computing for function printf_va_4 <- main.
-  Called from pthread_h.c:27.
+  Called from pthread_h.c:33.
 [eva] using specification for function printf_va_4
-[eva:alarm] pthread_h.c:27: Warning: 
+[eva:alarm] pthread_h.c:33: Warning: 
   function printf_va_4: precondition valid_read_string(param0) got status unknown.
-[eva] pthread_h.c:27: 
+[eva] pthread_h.c:33: 
   function printf_va_4: precondition valid_read_string(format) got status valid.
 [eva] Done for function printf_va_4
 [eva] computing for function start_routine <- main.
-  Called from pthread_h.c:32.
+  Called from pthread_h.c:38.
 [eva] computing for function printf_va_1 <- start_routine <- main.
-  Called from pthread_h.c:8.
+  Called from pthread_h.c:14.
 [eva] using specification for function printf_va_1
-[eva] pthread_h.c:8: function printf_va_1: precondition got status valid.
+[eva] pthread_h.c:14: function printf_va_1: precondition got status valid.
 [eva] Done for function printf_va_1
 [eva] Recording results for start_routine
 [eva] Done for function start_routine
 [eva] computing for function pthread_join <- main.
-  Called from pthread_h.c:34.
+  Called from pthread_h.c:40.
 [eva] using specification for function pthread_join
-[eva] pthread_h.c:34: 
+[eva] pthread_h.c:40: 
   function pthread_join: precondition 'valid_or_null_retval' got status valid.
 [eva] Done for function pthread_join
 [eva] computing for function printf_va_5 <- main.
-  Called from pthread_h.c:36.
+  Called from pthread_h.c:42.
 [eva] using specification for function printf_va_5
-[eva] pthread_h.c:36: function printf_va_5: precondition got status valid.
+[eva] pthread_h.c:42: function printf_va_5: precondition got status valid.
 [eva] Done for function printf_va_5
-[eva:alarm] pthread_h.c:39: Warning: 
+[eva:alarm] pthread_h.c:45: Warning: 
   out of bounds read. assert \valid_read(retv);
 [eva] computing for function printf_va_6 <- main.
-  Called from pthread_h.c:39.
+  Called from pthread_h.c:45.
 [eva] using specification for function printf_va_6
-[eva] pthread_h.c:39: function printf_va_6: precondition got status valid.
+[eva] pthread_h.c:45: function printf_va_6: precondition got status valid.
 [eva] Done for function printf_va_6
 [eva] Recording results for main
 [eva] Done for function main
diff --git a/tests/libc/oracle/pthread_h.1.res.oracle b/tests/libc/oracle/pthread_h.1.res.oracle
new file mode 100644
index 00000000000..e9962e514fb
--- /dev/null
+++ b/tests/libc/oracle/pthread_h.1.res.oracle
@@ -0,0 +1,94 @@
+[kernel] Parsing pthread_h.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
+  retval ∈ {0}
+  v ∈ [--..--]
+[eva] computing for function pthread_create <- main.
+  Called from pthread_h.c:23.
+[eva] using specification for function pthread_create
+[eva] pthread_h.c:23: 
+  function pthread_create: precondition 'valid_thread' got status valid.
+[eva] pthread_h.c:23: 
+  function pthread_create: precondition 'valid_null_attr' got status valid.
+[eva] pthread_h.c:23: 
+  function pthread_create: precondition 'valid_routine' got status valid.
+[eva] pthread_h.c:23: 
+  function pthread_create: precondition 'valid_null_arg' got status valid.
+[eva] Done for function pthread_create
+[eva] computing for function printf_va_2 <- main.
+  Called from pthread_h.c:25.
+[eva] using specification for function printf_va_2
+[eva] pthread_h.c:25: function printf_va_2: precondition got status valid.
+[eva] Done for function printf_va_2
+[eva] computing for function printf_va_3 <- main.
+  Called from pthread_h.c:28.
+[eva] using specification for function printf_va_3
+[eva] pthread_h.c:28: function printf_va_3: precondition got status valid.
+[eva] Done for function printf_va_3
+[eva:alarm] pthread_h.c:29: Warning: 
+  accessing uninitialized left-value. assert \initialized(&thread);
+[eva] computing for function pthread_setname_np <- main.
+  Called from pthread_h.c:29.
+[eva] using specification for function pthread_setname_np
+[eva] pthread_h.c:29: 
+  function pthread_setname_np: precondition 'valid_name' got status valid.
+[eva] Done for function pthread_setname_np
+[eva] computing for function pthread_getname_np <- main.
+  Called from pthread_h.c:32.
+[eva] using specification for function pthread_getname_np
+[eva] pthread_h.c:32: 
+  function pthread_getname_np: precondition 'valid_name' got status valid.
+[eva] Done for function pthread_getname_np
+[eva] computing for function printf_va_4 <- main.
+  Called from pthread_h.c:33.
+[eva] using specification for function printf_va_4
+[eva:alarm] pthread_h.c:33: Warning: 
+  function printf_va_4: precondition valid_read_string(param0) got status unknown.
+[eva] pthread_h.c:33: 
+  function printf_va_4: precondition valid_read_string(format) got status valid.
+[eva] Done for function printf_va_4
+[eva] computing for function start_routine <- main.
+  Called from pthread_h.c:38.
+[eva] computing for function printf_va_1 <- start_routine <- main.
+  Called from pthread_h.c:14.
+[eva] using specification for function printf_va_1
+[eva] pthread_h.c:14: function printf_va_1: precondition got status valid.
+[eva] Done for function printf_va_1
+[eva] Recording results for start_routine
+[eva] Done for function start_routine
+[eva] computing for function pthread_join <- main.
+  Called from pthread_h.c:40.
+[eva] using specification for function pthread_join
+[eva] pthread_h.c:40: 
+  function pthread_join: precondition 'valid_or_null_retval' got status valid.
+[eva] Done for function pthread_join
+[eva] computing for function printf_va_5 <- main.
+  Called from pthread_h.c:42.
+[eva] using specification for function printf_va_5
+[eva] pthread_h.c:42: function printf_va_5: precondition got status valid.
+[eva] Done for function printf_va_5
+[eva:alarm] pthread_h.c:45: Warning: 
+  out of bounds read. assert \valid_read(retv);
+[eva] computing for function printf_va_6 <- main.
+  Called from pthread_h.c:45.
+[eva] using specification for function printf_va_6
+[eva] pthread_h.c:45: function printf_va_6: precondition got status valid.
+[eva] Done for function printf_va_6
+[eva] Recording results for main
+[eva] Done for function main
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function start_routine:
+  retval ∈ {43}
+  __retres ∈ {{ (void *)&retval }}
+  S___fc_stdout[0..1] ∈ [--..--]
+[eva:final-states] Values at end of function main:
+  retval ∈ {0; 43}
+  thread ∈ [--..--] or UNINITIALIZED
+  thread_arg ∈ {42}
+  r ∈ [--..--]
+  buf[0..15] ∈ [--..--] or UNINITIALIZED
+  retv ∈ {{ NULL + [--..--] ; &retval }} or UNINITIALIZED
+  __retres ∈ {0; 1; 2}
+  S___fc_stdout[0..1] ∈ [--..--]
diff --git a/tests/libc/oracle/pthread_h.2.res.oracle b/tests/libc/oracle/pthread_h.2.res.oracle
new file mode 100644
index 00000000000..e4df7ae1f77
--- /dev/null
+++ b/tests/libc/oracle/pthread_h.2.res.oracle
@@ -0,0 +1,10 @@
+[kernel] Parsing pthread_h.c (with preprocessing)
+[kernel] pthread_h.c:49: User Error: 
+  cannot perform the following comparison thread == 0
+  47      // Test non-portable usage of pthread_t
+  48    #ifdef NON_PORTABLE
+  49      if (thread == 0) {
+              ^^^^^^^^^^^
+  50        return 2;
+  51      }
+[kernel] Frama-C aborted: invalid user input.
diff --git a/tests/libc/pthread_h.c b/tests/libc/pthread_h.c
index 28ba09c9d47..5b875173489 100644
--- a/tests/libc/pthread_h.c
+++ b/tests/libc/pthread_h.c
@@ -1,3 +1,9 @@
+/*run.config
+  STDOPT:
+  STDOPT: -cpp-extra-args="-D__FC_PTHREAD_T_IS_SCALAR -DNON_PORTABLE"
+  EXIT: 1
+  STDOPT: -cpp-extra-args="-DNON_PORTABLE"
+ */
 #define _GNU_SOURCE // if you want to compile with GCC
 #include <pthread.h>
 #include <stdio.h>
@@ -37,5 +43,13 @@ int main() {
     return 1;
   }
   printf("pthread_join succeeded, retval = %d\n", *retv);
+
+  // Test non-portable usage of pthread_t
+#ifdef NON_PORTABLE
+  if (thread == 0) {
+    return 2;
+  }
+#endif
+
   return 0;
 }
-- 
GitLab