[PATCH 1/1] newlib01: Check exit processing for file objects

Matthew Joyce matthew.joyce at embedded-brains.de
Wed Mar 23 11:36:03 UTC 2022


From: Matt Joyce <matthew.joyce at embedded-brains.de>

---
 testsuites/libtests/newlib01/init.c | 131 ++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 7 deletions(-)

diff --git a/testsuites/libtests/newlib01/init.c b/testsuites/libtests/newlib01/init.c
index 5864047a80..58757a7676 100644
--- a/testsuites/libtests/newlib01/init.c
+++ b/testsuites/libtests/newlib01/init.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2014, 2022 embedded brains GmbH.  All rights reserved.
  *
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
@@ -11,13 +11,16 @@
 #endif
 
 #include <stdio.h>
+#include <errno.h>
 
 #include <sys/reent.h>
+#include <sys/stat.h>
 
 #include <rtems.h>
 #include <rtems/console.h>
 #include <rtems/imfs.h>
 #include <rtems/libcsupport.h>
+#include <rtems/sysinit.h>
 
 #include "tmacros.h"
 
@@ -25,6 +28,15 @@ const char rtems_test_name[] = "NEWLIB 1";
 
 static const char file_path[] = "/file";
 
+static void test_sysinit_handler1(void);
+
+/*
+ * Test Newlib exit procedures. Allows us to place an exit handler at position
+ * 0, which is called after rtems_stdio_exit by Newlib's __call_exitprocs().
+ */
+RTEMS_SYSINIT_ITEM( test_sysinit_handler1, RTEMS_SYSINIT_STD_FILE_DESCRIPTORS,
+   RTEMS_SYSINIT_ORDER_FIRST );
+
 typedef enum {
   INIT,
   OPEN,
@@ -247,7 +259,45 @@ static const IMFS_node_control node_control = IMFS_GENERIC_INITIALIZER(
   IMFS_node_destroy_default
 );
 
-static void test(void)
+/*
+ * This exit handler will be called last among the functions registered with
+ * _atexit. Check that stdio file descriptors are closed. The cleanup handler
+ * has not yet run, so the stdio file objects themselves are still open.
+ */
+static void test_exit_handler1(void)
+{
+  struct stat buffer;
+  int status;
+
+  status = fstat(0, &buffer);
+  rtems_test_assert(status == -1);
+  rtems_test_assert(errno == EBADF);
+
+  status = fstat(1, &buffer);
+  rtems_test_assert(status == -1);
+  rtems_test_assert(errno == EBADF);
+
+  status = fstat(2, &buffer);
+  rtems_test_assert(status == -1);
+  rtems_test_assert(errno == EBADF);
+
+  rtems_test_assert( stdin->_flags != 0 );
+  rtems_test_assert( stdout->_flags != 0 );
+  rtems_test_assert( stderr->_flags != 0 );
+}
+
+/*
+ * Register test_exit_handler1 at position 0 in the _atexit _fns array.
+ * Thus, test_exit_handler1 will be called last--after rtems_libio_exit().
+ */
+static void test_sysinit_handler1(void)
+{
+  int rv;
+  rv = atexit(test_exit_handler1);
+  rtems_test_assert(rv == 0);
+}
+
+static void test_thread_specific_close(void)
 {
   test_context *ctx = &test_instance;
   rtems_status_code sc;
@@ -297,14 +347,79 @@ static void test(void)
   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
 }
 
+/*
+ * At this point, neither the _atexit functions nor __cleanup have been
+ * called. Therefore, stdio file descriptors should be open and stdio file
+ * object flags should be non-zero.
+ */
+static void test_exit_handling(void)
+{
+  struct stat buffer;
+  int status;
+
+  status = fstat(0, &buffer);
+  rtems_test_assert(status == 0);
+  rtems_test_assert(errno == 0);
+
+  status = fstat(1, &buffer);
+  rtems_test_assert(status == 0);
+  rtems_test_assert(errno == 0);
+
+  status = fstat(2, &buffer);
+  rtems_test_assert(status == 0);
+  rtems_test_assert(errno == 0);
+
+  rtems_test_assert( stdin->_flags != 0 );
+  rtems_test_assert( stdout->_flags != 0 );
+  rtems_test_assert( stderr->_flags != 0 );
+
+  /* Run exit handlers and __cleanup */
+  exit(0);
+}
+
 static void Init(rtems_task_argument arg)
 {
   TEST_BEGIN();
+  test_thread_specific_close();
+  test_exit_handling();
+}
 
-  test();
-
-  TEST_END();
-  rtems_test_exit(0);
+static void fatal_extension(
+  rtems_fatal_source source,
+  bool always_set_to_false,
+  rtems_fatal_code error
+)
+{
+  if (
+    source == RTEMS_FATAL_SOURCE_EXIT
+      && !always_set_to_false
+      && error == 0
+  ) {
+
+    /*
+     * Final conditions check after exit handlers and __cleanup have run.
+     * File descriptors and file objects themselves are closed.
+     */
+    struct stat buffer;
+    int status;
+
+    status = fstat(0, &buffer);
+    rtems_test_assert(status == -1);
+    rtems_test_assert(errno == EBADF);
+
+    status = fstat(1, &buffer);
+    rtems_test_assert(status == -1);
+    rtems_test_assert(errno == EBADF);
+
+    status = fstat(2, &buffer);
+    rtems_test_assert(status == -1);
+    rtems_test_assert(errno == EBADF);
+
+    rtems_test_assert( stdin->_flags == 0 );
+    rtems_test_assert( stdout->_flags == 0 );
+    rtems_test_assert( stderr->_flags == 0 );
+    TEST_END();
+  }
 }
 
 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
@@ -314,7 +429,9 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_MAXIMUM_TASKS 2
 
-#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+#define CONFIGURE_INITIAL_EXTENSIONS \
+  { .fatal = fatal_extension }, \
+  RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
 
-- 
2.31.1



More information about the devel mailing list