2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-27 15:18:06 +00:00

util: Introduce ovs_assert macro.

An occasionally significant problem with the standard "assert" macro is
that it writes the failure message to stderr.  In our daemons, stderr is
generally redirected to /dev/null.  It's more useful to write the failure
message to the log, which is what the new ovs_assert macro introduced in
this patch does.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Ethan Jackson <ethan@nicira.com>
This commit is contained in:
Ben Pfaff
2013-01-16 16:03:03 -08:00
parent 1677446238
commit 4749f73d12
5 changed files with 102 additions and 4 deletions

View File

@@ -26,6 +26,8 @@
#define ALWAYS_INLINE __attribute__((always_inline))
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
#define SENTINEL(N) __attribute__((sentinel(N)))
#define OVS_LIKELY(CONDITION) __builtin_expect(!!(CONDITION), 1)
#define OVS_UNLIKELY(CONDITION) __builtin_expect(!!(CONDITION), 0)
#else
#define NO_RETURN
#define OVS_UNUSED
@@ -35,6 +37,8 @@
#define ALWAYS_INLINE
#define WARN_UNUSED_RESULT
#define SENTINEL(N)
#define OVS_LIKELY(CONDITION) (!!(CONDITION))
#define OVS_UNLIKELY(CONDITION) (!!(CONDITION))
#endif
/* ISO C says that a C implementation may choose any integer type for an enum

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
#include <config.h>
#include "util.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
@@ -45,6 +44,30 @@ const char *subprogram_name = "";
/* --version option output. */
static char *program_version;
void
ovs_assert_failure(const char *where, const char *function,
const char *condition)
{
/* Prevent an infinite loop (or stack overflow) in case VLOG_ABORT happens
* to trigger an assertion failure of its own. */
static int reentry = 0;
switch (reentry++) {
case 0:
VLOG_ABORT("%s: assertion %s failed in %s()",
where, condition, function);
NOT_REACHED();
case 1:
fprintf(stderr, "%s: assertion %s failed in %s()",
where, condition, function);
abort();
default:
abort();
}
}
void
out_of_memory(void)
{
@@ -756,7 +779,7 @@ english_list_delimiter(size_t index, size_t total)
int
log_2_floor(uint32_t n)
{
assert(n);
ovs_assert(n);
#if !defined(UINT_MAX) || !defined(UINT32_MAX)
#error "Someone screwed up the #includes."

View File

@@ -62,6 +62,17 @@
#define BUILD_ASSERT_DECL_GCCONLY(EXPR) ((void) 0)
#endif
/* Like the standard assert macro, except:
*
* - Writes the failure message to the log.
*
* - Not affected by NDEBUG. */
#define ovs_assert(CONDITION) \
if (!OVS_LIKELY(CONDITION)) { \
ovs_assert_failure(SOURCE_LOCATOR, __func__, #CONDITION); \
}
void ovs_assert_failure(const char *, const char *, const char *) NO_RETURN;
/* Casts 'pointer' to 'type' and issues a compiler warning if the cast changes
* anything other than an outermost "const" or "volatile" qualifier.
*

View File

@@ -140,3 +140,22 @@ mkdir 01234567890123456789012345678901234567890123456789012345678901234567890123
cd 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
AT_CHECK([test-unix-socket ../012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/socket socket])
AT_CLEANUP
AT_SETUP([ovs_assert])
OVS_LOGDIR=`pwd`; export OVS_LOGDIR
AT_CHECK([test-util -voff -vfile:info '-vPATTERN:file:%c|%p|%m' --log-file assert || kill -l $?],
[0], [ABRT
], [stderr])
AT_CHECK([sed 's/\(opened log file\) .*/\1/
s/|[[^|]]*: /|/' test-util.log], [0], [dnl
vlog|INFO|opened log file
util|EMER|assertion false failed in test_assert()
])
AT_CHECK([sed 's/.*: //
1q' stderr], [0],
[assertion false failed in test_assert()
])
AT_CLEANUP

View File

@@ -16,6 +16,7 @@
#include <config.h>
#include <getopt.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
@@ -25,6 +26,7 @@
#include "command-line.h"
#include "random.h"
#include "util.h"
#include "vlog.h"
#undef NDEBUG
#include <assert.h>
@@ -335,6 +337,12 @@ test_follow_symlinks(int argc, char *argv[])
free(target);
}
}
static void
test_assert(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
ovs_assert(false);
}
static const struct command commands[] = {
{"ctz", 0, 0, test_ctz},
@@ -345,13 +353,46 @@ static const struct command commands[] = {
{"bitwise_one", 0, 0, test_bitwise_one},
{"bitwise_is_all_zeros", 0, 0, test_bitwise_is_all_zeros},
{"follow-symlinks", 1, INT_MAX, test_follow_symlinks},
{"assert", 0, 0, test_assert},
{NULL, 0, 0, NULL},
};
static void
parse_options(int argc, char *argv[])
{
enum {
VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
VLOG_LONG_OPTIONS,
{NULL, 0, NULL, 0},
};
char *short_options = long_options_to_short_options(long_options);
for (;;) {
int c = getopt_long(argc, argv, short_options, long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
VLOG_OPTION_HANDLERS
case '?':
exit(EXIT_FAILURE);
default:
abort();
}
}
free(short_options);
}
int
main(int argc, char *argv[])
{
set_program_name(argv[0]);
run_command(argc - 1, argv + 1, commands);
parse_options(argc, argv);
run_command(argc - optind, argv + optind, commands);
return 0;
}