mirror of
git://sourceware.org/git/glibc.git
synced 2025-03-06 20:58:33 +01:00
assert: ensure posix compliance, add tests for such
Fix assert.c so that even the fallback case conforms to POSIX, although not exactly the same as the default case so a test can tell the difference. Add a test that verifies that abort is called, and that the message printed to stderr has all the info that POSIX requires. Verify this even when malloc isn't usable. Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
This commit is contained in:
parent
b3a7a15d99
commit
e79e5c4899
3 changed files with 198 additions and 2 deletions
|
@ -38,6 +38,7 @@ tests := \
|
||||||
test-assert-perr \
|
test-assert-perr \
|
||||||
tst-assert-c++ \
|
tst-assert-c++ \
|
||||||
tst-assert-g++ \
|
tst-assert-g++ \
|
||||||
|
test-assert-2 \
|
||||||
# tests
|
# tests
|
||||||
|
|
||||||
ifeq ($(have-cxx-thread_local),yes)
|
ifeq ($(have-cxx-thread_local),yes)
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <setvmaname.h>
|
#include <setvmaname.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <intprops.h>
|
||||||
|
|
||||||
|
|
||||||
extern const char *__progname;
|
extern const char *__progname;
|
||||||
|
@ -87,8 +89,35 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* At least print a minimal message. */
|
/* At least print a minimal message. */
|
||||||
static const char errstr[] = "Unexpected error.\n";
|
char linebuf[INT_STRLEN_BOUND (int) + sizeof ":: "];
|
||||||
__libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
|
struct iovec v[9];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
#define WS(s) (v[i].iov_len = strlen (v[i].iov_base = (void *) (s)), i++)
|
||||||
|
|
||||||
|
if (__progname)
|
||||||
|
{
|
||||||
|
WS (__progname);
|
||||||
|
WS (": ");
|
||||||
|
}
|
||||||
|
|
||||||
|
WS (file);
|
||||||
|
v[i++] = (struct iovec) {.iov_base = linebuf,
|
||||||
|
.iov_len = sprintf (linebuf, ":%d: ", line)};
|
||||||
|
|
||||||
|
if (function)
|
||||||
|
{
|
||||||
|
WS (function);
|
||||||
|
WS (": ");
|
||||||
|
}
|
||||||
|
|
||||||
|
WS ("Assertion `");
|
||||||
|
WS (assertion);
|
||||||
|
/* We omit the '.' here so that the assert tests can tell when
|
||||||
|
this code path is taken. */
|
||||||
|
WS ("' failed\n");
|
||||||
|
|
||||||
|
(void) writev (STDERR_FILENO, v, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
abort ();
|
abort ();
|
||||||
|
|
166
assert/test-assert-2.c
Normal file
166
assert/test-assert-2.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/* Test assert's compliance with POSIX requirements.
|
||||||
|
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; 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; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library 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.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* This test verifies that a failed assertion acts in accordance with
|
||||||
|
the POSIX requirements, despite any internal failures. We do so by
|
||||||
|
calling test routines via fork() and monitoring their exit codes
|
||||||
|
and stderr, while possibly forcing internal functions (malloc) to
|
||||||
|
fail. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#undef NDEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <support/check.h>
|
||||||
|
#include <support/support.h>
|
||||||
|
#include <support/capture_subprocess.h>
|
||||||
|
#include <support/xstdio.h>
|
||||||
|
|
||||||
|
/* We need to be able to make malloc() "fail" so that __asprintf
|
||||||
|
fails. */
|
||||||
|
|
||||||
|
void * (*next_malloc)(size_t sz) = 0;
|
||||||
|
static volatile bool fail_malloc = 0;
|
||||||
|
|
||||||
|
void *
|
||||||
|
malloc (size_t sz)
|
||||||
|
{
|
||||||
|
if (fail_malloc)
|
||||||
|
return NULL;
|
||||||
|
if (next_malloc == 0)
|
||||||
|
next_malloc = dlsym (RTLD_NEXT, "malloc");
|
||||||
|
if (next_malloc == 0)
|
||||||
|
return NULL;
|
||||||
|
return next_malloc (sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can tell if abort() is called by looking for the custom return
|
||||||
|
value. */
|
||||||
|
|
||||||
|
void
|
||||||
|
abort_handler(int s)
|
||||||
|
{
|
||||||
|
_exit(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_lineno;
|
||||||
|
static const char *do_funcname;
|
||||||
|
|
||||||
|
/* Hack to get the line of the assert. */
|
||||||
|
#define GET_INFO_1(l) \
|
||||||
|
if (closure != NULL) \
|
||||||
|
{ \
|
||||||
|
do_lineno = l; \
|
||||||
|
do_funcname = __func__; \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
#define GET_INFO() GET_INFO_1(__LINE__+1)
|
||||||
|
|
||||||
|
/* These are the two test cases. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_assert_normal (void *closure)
|
||||||
|
{
|
||||||
|
if (closure == NULL)
|
||||||
|
signal (SIGABRT, abort_handler);
|
||||||
|
|
||||||
|
GET_INFO ();
|
||||||
|
assert (1 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_assert_nomalloc (void *closure)
|
||||||
|
{
|
||||||
|
if (closure == NULL)
|
||||||
|
{
|
||||||
|
signal (SIGABRT, abort_handler);
|
||||||
|
fail_malloc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_INFO ();
|
||||||
|
assert (1 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_posix (const char *buf, int rv, int line,
|
||||||
|
const char *funcname, const char *testarg)
|
||||||
|
{
|
||||||
|
/* POSIX requires that a failed assertion write a diagnostic to
|
||||||
|
stderr and call abort. The diagnostic must include the filename,
|
||||||
|
line number, and function where the assertion failed, along with
|
||||||
|
the text of the assert() argument.
|
||||||
|
*/
|
||||||
|
char linestr[100];
|
||||||
|
|
||||||
|
sprintf (linestr, "%d", line);
|
||||||
|
|
||||||
|
/* If abort is called, our handler will return 5. */
|
||||||
|
TEST_VERIFY (rv == 5);
|
||||||
|
|
||||||
|
TEST_VERIFY (strstr (buf, __FILE__) != NULL);
|
||||||
|
TEST_VERIFY (strstr (buf, linestr) != NULL);
|
||||||
|
TEST_VERIFY (strstr (buf, funcname) != NULL);
|
||||||
|
TEST_VERIFY (strstr (buf, testarg) != NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
one_test (void (*func)(void *), int which_path)
|
||||||
|
{
|
||||||
|
struct support_capture_subprocess sp;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
func (&do_lineno);
|
||||||
|
printf("running test for %s, line %d\n", do_funcname, do_lineno);
|
||||||
|
|
||||||
|
sp = support_capture_subprocess (func, NULL);
|
||||||
|
rv = WEXITSTATUS (sp.status);
|
||||||
|
|
||||||
|
check_posix (sp.err.buffer, rv, do_lineno, do_funcname, "1 == 2");
|
||||||
|
|
||||||
|
/* Look for intentional subtle differences in messages to verify
|
||||||
|
that the intended code path was taken. */
|
||||||
|
switch (which_path)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
TEST_VERIFY (strstr (sp.err.buffer, "failed\n") != NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
support_capture_subprocess_free (&sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test(void)
|
||||||
|
{
|
||||||
|
one_test (test_assert_normal, 0);
|
||||||
|
one_test (test_assert_nomalloc, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <support/test-driver.c>
|
Loading…
Add table
Reference in a new issue