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

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Mar 24 08:19:10 UTC 2022


On 23/03/2022 12:36, Matthew Joyce wrote:
> 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 );
> +

Please move the RTEMS_SYSINIT_ITEM() below the test_sysinit_handler1() 
definition. Only use 1 if there is at least a 2. Maybe name the handler 
register_exit_handler_before_libio_exit().

>   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);

If you test an errno value, always set it before the function to some 
other value, for example

errno = 0;
status = fstat(0, &buffer);

> +
> +  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);
> +}

Maybe rename test_exit_handler1() in check_after_libio_exit().

> +
> +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);

There is no need to check for errno == 0. In fact, since fstat() is not 
supposed to write to errno if it is successful, this check could fail 
depending on what the test did before.

> +
> +  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.
> +     */

Please remove all Newlib internal names from the comments to avoid out 
dated comments if the Newlib internals change.

> +    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
>   

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber at embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/


More information about the devel mailing list