tests: Test EBADF and errno handling when closing fds

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2022-10-31 10:47:34 +00:00
parent 81130a6e3f
commit f1f711dc77

View File

@ -2470,6 +2470,64 @@ assert_fd_was_closed (int fd)
}
}
static void
test_clear_fd_ebadf (void)
{
char *name = NULL;
GError *error = NULL;
int fd;
int copy_of_fd;
int errsv;
gboolean ret;
/* We're going to trigger a programming error: attmpting to close a
* fd that was already closed. Make criticals non-fatal. */
g_assert_true (g_test_undefined ());
g_log_set_always_fatal (G_LOG_FATAL_MASK);
g_log_set_fatal_mask ("GLib", G_LOG_FATAL_MASK);
fd = g_file_open_tmp (NULL, &name, &error);
g_assert_cmpint (fd, !=, -1);
g_assert_no_error (error);
g_assert_nonnull (name);
ret = g_close (fd, &error);
g_assert_no_error (error);
assert_fd_was_closed (fd);
g_assert_true (ret);
g_unlink (name);
g_free (name);
/* Try to close it again with g_close() */
ret = g_close (fd, NULL);
errsv = errno;
g_assert_cmpint (errsv, ==, EBADF);
assert_fd_was_closed (fd);
g_assert_false (ret);
/* Try to close it again with g_clear_fd() */
copy_of_fd = fd;
errno = EILSEQ;
ret = g_clear_fd (&copy_of_fd, NULL);
errsv = errno;
g_assert_cmpint (errsv, ==, EBADF);
assert_fd_was_closed (fd);
g_assert_false (ret);
#ifdef g_autofree
{
g_autofd int close_me = fd;
/* This avoids clang warnings about the variables being unused */
g_test_message ("Invalid fd will be closed by autocleanup: %d",
close_me);
errno = EILSEQ;
}
errsv = errno;
g_assert_cmpint (errsv, ==, EILSEQ);
#endif
}
static void
test_clear_fd (void)
{
@ -2477,6 +2535,7 @@ test_clear_fd (void)
GError *error = NULL;
int fd;
int copy_of_fd;
int errsv;
#ifdef g_autofree
g_test_summary ("Test g_clear_fd() and g_autofd");
@ -2522,12 +2581,31 @@ test_clear_fd (void)
/* This avoids clang warnings about the variables being unused */
g_test_message ("Will be closed by autocleanup: %d, %d",
close_me, was_never_set);
/* This is one of the few errno values guaranteed by Standard C.
* We set it here to check that a successful g_autofd close doesn't
* alter errno. */
errno = EILSEQ;
}
errsv = errno;
g_assert_cmpint (errsv, ==, EILSEQ);
assert_fd_was_closed (fd);
g_unlink (name);
g_free (name);
#endif
if (g_test_undefined ())
{
g_test_message ("Testing error handling");
g_test_trap_subprocess ("/fileutils/clear-fd/subprocess/ebadf",
0, G_TEST_SUBPROCESS_DEFAULT);
#ifdef g_autofree
g_test_trap_assert_stderr ("*failed with EBADF*failed with EBADF*failed with EBADF*");
#else
g_test_trap_assert_stderr ("*failed with EBADF*failed with EBADF*");
#endif
g_test_trap_assert_passed ();
}
}
int
@ -2567,6 +2645,7 @@ main (int argc,
g_test_add_func ("/fileutils/stdio-wrappers", test_stdio_wrappers);
g_test_add_func ("/fileutils/fopen-modes", test_fopen_modes);
g_test_add_func ("/fileutils/clear-fd", test_clear_fd);
g_test_add_func ("/fileutils/clear-fd/subprocess/ebadf", test_clear_fd_ebadf);
return g_test_run ();
}